DF-4970 / dingo_flags.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | /* * DF-4970 harness: proves the XE_CARD_TYPE_FLAGS_DINGO (0x4) case in * xe_pccard_probe()'s flag-propagation loop is DEAD CODE, so CEM56/REM56 * "Dingo" combo cards never get scp->dingo set. * * Everything below the MODEL marker is transcribed verbatim from * sys/dev/netif/xe/if_xe_pccard.c (lines 90-127 and 311-323) plus the two * loop variants under test (stock `!=` vs fixed `<=`). * * Build: cc -O -o dingo_flags dingo_flags.c * Run: ./dingo_flags (exit 0 = invariants hold, 1 = violation) */ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> /* ---------------- verbatim from if_xe_pccard.c ---------------- */ #define XE_CARD_TYPE_FLAGS_NO 0x0 #define XE_CARD_TYPE_FLAGS_CE2 0x1 #define XE_CARD_TYPE_FLAGS_MOHAWK 0x2 #define XE_CARD_TYPE_FLAGS_DINGO 0x4 #define XE_PROD_UMASK 0x11000f #define XE_PROD_SINGLE_ID1 0x010001 #define XE_PROD_SINGLE_ID2 0x010002 #define XE_PROD_SINGLE_ID3 0x010003 #define XE_PROD_MULTI_ID1 0x110001 #define XE_PROD_MULTI_ID2 0x110002 #define XE_PROD_MULTI_ID3 0x110003 #define XE_PROD_MULTI_ID4 0x110004 #define XE_PROD_MULTI_ID5 0x110005 #define XE_PROD_MULTI_ID6 0x110006 #define XE_PROD_MULTI_ID7 0x110007 struct xe_card_type { uint32_t prod_type; const char *card_type_desc; uint32_t flags; } xe_card_types[] = { { XE_PROD_MULTI_ID1, "CEM", XE_CARD_TYPE_FLAGS_NO }, { XE_PROD_MULTI_ID2, "CEM2", XE_CARD_TYPE_FLAGS_CE2 }, { XE_PROD_MULTI_ID3, "CEM3", XE_CARD_TYPE_FLAGS_CE2 }, { XE_PROD_MULTI_ID4, "CEM33", XE_CARD_TYPE_FLAGS_CE2 }, { XE_PROD_MULTI_ID5, "CEM56M", XE_CARD_TYPE_FLAGS_MOHAWK }, { XE_PROD_MULTI_ID6, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK | XE_CARD_TYPE_FLAGS_DINGO }, { XE_PROD_MULTI_ID7, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK | XE_CARD_TYPE_FLAGS_DINGO }, { XE_PROD_SINGLE_ID1, "CE", XE_CARD_TYPE_FLAGS_NO }, { XE_PROD_SINGLE_ID2, "CE2", XE_CARD_TYPE_FLAGS_CE2 }, { XE_PROD_SINGLE_ID3, "CE3", XE_CARD_TYPE_FLAGS_MOHAWK }, { 0, NULL, -1 } }; /* softc fields written by the loop (if_xevar.h) */ struct scp_model { int ce2, mohawk, dingo; }; static struct xe_card_type * xe_card_type_lookup(uint32_t prod) /* verbatim */ { struct xe_card_type *ct; for (ct = xe_card_types; ct->card_type_desc != NULL; ++ct) { if(ct->prod_type == (prod & XE_PROD_UMASK)) return ct; } return NULL; } /* ---------------- the loop under test, two variants ------------- */ static void probe_flags_stock(struct scp_model *scp, struct xe_card_type *card_itm) { int i; scp->ce2 = scp->mohawk = scp->dingo = 0; /* stock if_xe_pccard.c:311 */ for (i = 1; i != XE_CARD_TYPE_FLAGS_DINGO; i = i << 1) { switch(i & card_itm->flags) { case XE_CARD_TYPE_FLAGS_CE2: scp->ce2 = 1; break; case XE_CARD_TYPE_FLAGS_MOHAWK: scp->mohawk = 1; break; case XE_CARD_TYPE_FLAGS_DINGO: scp->dingo = 1; break; } } } static void probe_flags_fixed(struct scp_model *scp, struct xe_card_type *card_itm) { int i; scp->ce2 = scp->mohawk = scp->dingo = 0; /* proposed fix: iterate through the DINGO bit as well */ for (i = 1; i <= XE_CARD_TYPE_FLAGS_DINGO; i = i << 1) { switch(i & card_itm->flags) { case XE_CARD_TYPE_FLAGS_CE2: scp->ce2 = 1; break; case XE_CARD_TYPE_FLAGS_MOHAWK: scp->mohawk = 1; break; case XE_CARD_TYPE_FLAGS_DINGO: scp->dingo = 1; break; } } } int main(void) { static const uint32_t prods[] = { XE_PROD_SINGLE_ID1, XE_PROD_SINGLE_ID2, XE_PROD_SINGLE_ID3, XE_PROD_MULTI_ID1, XE_PROD_MULTI_ID2, XE_PROD_MULTI_ID3, XE_PROD_MULTI_ID4, XE_PROD_MULTI_ID5, XE_PROD_MULTI_ID6, XE_PROD_MULTI_ID7, }; int rc = 0, dingo_seen_stock = 0; printf("%-10s %-8s %s\n", "prod", "card", "flags (ce2,mohawk,dingo)"); for (size_t k = 0; k < sizeof(prods)/sizeof(prods[0]); k++) { struct xe_card_type *ct = xe_card_type_lookup(prods[k]); struct scp_model s, f; if (ct == NULL) { printf("0x%06x LOOKUP-FAIL\n", prods[k]); rc = 1; continue; } probe_flags_stock(&s, ct); probe_flags_fixed(&f, ct); dingo_seen_stock |= s.dingo; { char left[32], right[32]; snprintf(left, sizeof left, "%d,%d,%d", s.ce2, s.mohawk, s.dingo); snprintf(right, sizeof right, "%d,%d,%d", f.ce2, f.mohawk, f.dingo); printf("0x%06x %-8s ce2,mohawk,dingo stock=%-10s fixed=%s\n", prods[k], ct->card_type_desc, left, right); } /* invariant: entries whose table flags include DINGO (CEM56 * MULTI_ID6/ID7) must end with dingo set -- required by * xe_cemfix (if_xe_pccard.c:201-208) and xe_activate's * RealPort aligned-port path (if_xe.c:1915+). */ if ((ct->flags & XE_CARD_TYPE_FLAGS_DINGO) && !s.dingo) { printf(" VIOLATION: %s is a Dingo card but " "scp->dingo == 0 in the STOCK loop\n", ct->card_type_desc); rc = 1; } if ((ct->flags & XE_CARD_TYPE_FLAGS_DINGO) && !f.dingo) { printf(" VIOLATION: fix failed for %s\n", ct->card_type_desc); rc = 1; } } printf("\nstock loop ever sets dingo: %s\n", dingo_seen_stock ? "yes" : "NO (case is dead code)"); printf("%s\n", rc == 0 ? "RESULT: invariants hold (dead case confirmed by table)" : "RESULT: VIOLATIONS FOUND"); return rc; } |