/*
 * DF-3910 trigger/analysis — divide-by-zero panic in
 * tonga_thermal_setup_fan_table() (sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:2502-2513)
 *
 * Kernel path (hardware-gated: Tonga/Fiji + crafted VBIOS fan table):
 *   process_pptables_v1_0.c copies usTMin/usTMed/usTHigh verbatim from the
 *   ATOM_Tonga_Fan_Table / ATOM_Fiji_Fan_Table with no ordering or
 *   distinctness validation (process_pptables_v1_0.c:941-986).  If the VBIOS
 *   supplies usTMed == usTMin (or usTHigh == usTMed), then
 *       t_diff1 = usTMed - usTMin;      (== 0)
 *       slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
 *   divides by zero -> #DE -> kernel panic during DPM enable
 *   (tonga_thermal_setup_fan_table is invoked from the enable task list).
 *   Known DF-1274 covered only the SCLK/MCLK spread-spectrum rates
 *   (tonga_smumgr.c:591/883); this fan-table site was not covered.
 *   Per-file twins already filed: ci DF-1297, iceland DF-1323, fiji DF-1325,
 *   polaris10 DF-1345.
 *
 * This harness performs the identical arithmetic in userspace: t_diff == 0
 * raises SIGFPE exactly the way the kernel path raises #DE.
 */
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

static volatile sig_atomic_t got_fpe;

static void fh(int sig) { (void)sig; got_fpe = 1; _exit(42); }

int main(void)
{
    uint32_t duty100   = 200;   /* CG_FDO_CTRL1.FMAX_DUTY100, non-zero on hw */
    uint32_t pwm_diff1 = 1234;  /* usPWMMed - usPWMMin                    */
    uint32_t usTMin = 4000, usTMed = 4000;  /* crafted VBIOS: TMed == TMin */
    uint32_t t_diff1 = usTMed - usTMin;     /* == 0                        */

    signal(SIGFPE, fh);
    printf("duty100=%u pwm_diff1=%u usTMin=%u usTMed=%u -> t_diff1=%u\n",
           duty100, pwm_diff1, usTMin, usTMed, t_diff1);
    printf("evaluating (50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100 ...\n");
    fflush(stdout);
    uint16_t slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
    printf("no fault, slope1=%u (unexpected)\n", slope1);
    return 0; /* exit 42 via fh() == fault demonstrated */
}
