1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2023 Advanced Micro Devices, Inc */
3 
4 #include "core.h"
5 
6 int pdsc_setup(struct pdsc *pdsc, bool init)
7 {
8 	int err = 0;
9 
10 	if (init)
11 		err = pdsc_dev_init(pdsc);
12 	else
13 		err = pdsc_dev_reinit(pdsc);
14 	if (err)
15 		return err;
16 
17 	clear_bit(PDSC_S_FW_DEAD, &pdsc->state);
18 	return 0;
19 }
20 
21 void pdsc_teardown(struct pdsc *pdsc, bool removing)
22 {
23 	pdsc_devcmd_reset(pdsc);
24 
25 	if (removing) {
26 		kfree(pdsc->intr_info);
27 		pdsc->intr_info = NULL;
28 	}
29 
30 	if (pdsc->kern_dbpage) {
31 		iounmap(pdsc->kern_dbpage);
32 		pdsc->kern_dbpage = NULL;
33 	}
34 
35 	set_bit(PDSC_S_FW_DEAD, &pdsc->state);
36 }
37 
38 static void pdsc_fw_down(struct pdsc *pdsc)
39 {
40 	if (test_and_set_bit(PDSC_S_FW_DEAD, &pdsc->state)) {
41 		dev_err(pdsc->dev, "%s: already happening\n", __func__);
42 		return;
43 	}
44 
45 	pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY);
46 }
47 
48 static void pdsc_fw_up(struct pdsc *pdsc)
49 {
50 	int err;
51 
52 	if (!test_bit(PDSC_S_FW_DEAD, &pdsc->state)) {
53 		dev_err(pdsc->dev, "%s: fw not dead\n", __func__);
54 		return;
55 	}
56 
57 	err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY);
58 	if (err)
59 		goto err_out;
60 
61 	return;
62 
63 err_out:
64 	pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY);
65 }
66 
67 void pdsc_health_thread(struct work_struct *work)
68 {
69 	struct pdsc *pdsc = container_of(work, struct pdsc, health_work);
70 	unsigned long mask;
71 	bool healthy;
72 
73 	mutex_lock(&pdsc->config_lock);
74 
75 	/* Don't do a check when in a transition state */
76 	mask = BIT_ULL(PDSC_S_INITING_DRIVER) |
77 	       BIT_ULL(PDSC_S_STOPPING_DRIVER);
78 	if (pdsc->state & mask)
79 		goto out_unlock;
80 
81 	healthy = pdsc_is_fw_good(pdsc);
82 	dev_dbg(pdsc->dev, "%s: health %d fw_status %#02x fw_heartbeat %d\n",
83 		__func__, healthy, pdsc->fw_status, pdsc->last_hb);
84 
85 	if (test_bit(PDSC_S_FW_DEAD, &pdsc->state)) {
86 		if (healthy)
87 			pdsc_fw_up(pdsc);
88 	} else {
89 		if (!healthy)
90 			pdsc_fw_down(pdsc);
91 	}
92 
93 	pdsc->fw_generation = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION;
94 
95 out_unlock:
96 	mutex_unlock(&pdsc->config_lock);
97 }
98