xref: /linux/drivers/soc/xilinx/xlnx_event_manager.c (revision c7fdb2404f66131bc9c22e06f712717288826487)
1*c7fdb240SAbhyuday Godhasara // SPDX-License-Identifier: GPL-2.0
2*c7fdb240SAbhyuday Godhasara /*
3*c7fdb240SAbhyuday Godhasara  * Xilinx Event Management Driver
4*c7fdb240SAbhyuday Godhasara  *
5*c7fdb240SAbhyuday Godhasara  *  Copyright (C) 2021 Xilinx, Inc.
6*c7fdb240SAbhyuday Godhasara  *
7*c7fdb240SAbhyuday Godhasara  *  Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
8*c7fdb240SAbhyuday Godhasara  */
9*c7fdb240SAbhyuday Godhasara 
10*c7fdb240SAbhyuday Godhasara #include <linux/cpuhotplug.h>
11*c7fdb240SAbhyuday Godhasara #include <linux/firmware/xlnx-event-manager.h>
12*c7fdb240SAbhyuday Godhasara #include <linux/firmware/xlnx-zynqmp.h>
13*c7fdb240SAbhyuday Godhasara #include <linux/hashtable.h>
14*c7fdb240SAbhyuday Godhasara #include <linux/interrupt.h>
15*c7fdb240SAbhyuday Godhasara #include <linux/irq.h>
16*c7fdb240SAbhyuday Godhasara #include <linux/irqdomain.h>
17*c7fdb240SAbhyuday Godhasara #include <linux/module.h>
18*c7fdb240SAbhyuday Godhasara #include <linux/of_irq.h>
19*c7fdb240SAbhyuday Godhasara #include <linux/platform_device.h>
20*c7fdb240SAbhyuday Godhasara #include <linux/slab.h>
21*c7fdb240SAbhyuday Godhasara 
22*c7fdb240SAbhyuday Godhasara static DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number1);
23*c7fdb240SAbhyuday Godhasara 
24*c7fdb240SAbhyuday Godhasara static int virq_sgi;
25*c7fdb240SAbhyuday Godhasara static int event_manager_availability = -EACCES;
26*c7fdb240SAbhyuday Godhasara 
27*c7fdb240SAbhyuday Godhasara /* SGI number used for Event management driver */
28*c7fdb240SAbhyuday Godhasara #define XLNX_EVENT_SGI_NUM	(15)
29*c7fdb240SAbhyuday Godhasara 
30*c7fdb240SAbhyuday Godhasara /* Max number of driver can register for same event */
31*c7fdb240SAbhyuday Godhasara #define MAX_DRIVER_PER_EVENT	(10U)
32*c7fdb240SAbhyuday Godhasara 
33*c7fdb240SAbhyuday Godhasara /* Max HashMap Order for PM API feature check (1<<7 = 128) */
34*c7fdb240SAbhyuday Godhasara #define REGISTERED_DRIVER_MAX_ORDER	(7)
35*c7fdb240SAbhyuday Godhasara 
36*c7fdb240SAbhyuday Godhasara #define MAX_BITS	(32U) /* Number of bits available for error mask */
37*c7fdb240SAbhyuday Godhasara 
38*c7fdb240SAbhyuday Godhasara #define FIRMWARE_VERSION_MASK			(0xFFFFU)
39*c7fdb240SAbhyuday Godhasara #define REGISTER_NOTIFIER_FIRMWARE_VERSION	(2U)
40*c7fdb240SAbhyuday Godhasara 
41*c7fdb240SAbhyuday Godhasara static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
42*c7fdb240SAbhyuday Godhasara static int sgi_num = XLNX_EVENT_SGI_NUM;
43*c7fdb240SAbhyuday Godhasara 
44*c7fdb240SAbhyuday Godhasara /**
45*c7fdb240SAbhyuday Godhasara  * struct registered_event_data - Registered Event Data.
46*c7fdb240SAbhyuday Godhasara  * @key:		key is the combine id(Node-Id | Event-Id) of type u64
47*c7fdb240SAbhyuday Godhasara  *			where upper u32 for Node-Id and lower u32 for Event-Id,
48*c7fdb240SAbhyuday Godhasara  *			And this used as key to index into hashmap.
49*c7fdb240SAbhyuday Godhasara  * @agent_data:		Data passed back to handler function.
50*c7fdb240SAbhyuday Godhasara  * @cb_type:		Type of Api callback, like PM_NOTIFY_CB, etc.
51*c7fdb240SAbhyuday Godhasara  * @eve_cb:		Function pointer to store the callback function.
52*c7fdb240SAbhyuday Godhasara  * @wake:		If this flag set, firmware will wakeup processor if is
53*c7fdb240SAbhyuday Godhasara  *			in sleep or power down state.
54*c7fdb240SAbhyuday Godhasara  * @hentry:		hlist_node that hooks this entry into hashtable.
55*c7fdb240SAbhyuday Godhasara  */
56*c7fdb240SAbhyuday Godhasara struct registered_event_data {
57*c7fdb240SAbhyuday Godhasara 	u64 key;
58*c7fdb240SAbhyuday Godhasara 	enum pm_api_cb_id cb_type;
59*c7fdb240SAbhyuday Godhasara 	void *agent_data;
60*c7fdb240SAbhyuday Godhasara 
61*c7fdb240SAbhyuday Godhasara 	event_cb_func_t eve_cb;
62*c7fdb240SAbhyuday Godhasara 	bool wake;
63*c7fdb240SAbhyuday Godhasara 	struct hlist_node hentry;
64*c7fdb240SAbhyuday Godhasara };
65*c7fdb240SAbhyuday Godhasara 
66*c7fdb240SAbhyuday Godhasara static bool xlnx_is_error_event(const u32 node_id)
67*c7fdb240SAbhyuday Godhasara {
68*c7fdb240SAbhyuday Godhasara 	if (node_id == EVENT_ERROR_PMC_ERR1 ||
69*c7fdb240SAbhyuday Godhasara 	    node_id == EVENT_ERROR_PMC_ERR2 ||
70*c7fdb240SAbhyuday Godhasara 	    node_id == EVENT_ERROR_PSM_ERR1 ||
71*c7fdb240SAbhyuday Godhasara 	    node_id == EVENT_ERROR_PSM_ERR2)
72*c7fdb240SAbhyuday Godhasara 		return true;
73*c7fdb240SAbhyuday Godhasara 
74*c7fdb240SAbhyuday Godhasara 	return false;
75*c7fdb240SAbhyuday Godhasara }
76*c7fdb240SAbhyuday Godhasara 
77*c7fdb240SAbhyuday Godhasara static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, const bool wake,
78*c7fdb240SAbhyuday Godhasara 					event_cb_func_t cb_fun,	void *data)
79*c7fdb240SAbhyuday Godhasara {
80*c7fdb240SAbhyuday Godhasara 	u64 key = 0;
81*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
82*c7fdb240SAbhyuday Godhasara 
83*c7fdb240SAbhyuday Godhasara 	key = ((u64)node_id << 32U) | (u64)event;
84*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given key id */
85*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
86*c7fdb240SAbhyuday Godhasara 		if (eve_data->key == key) {
87*c7fdb240SAbhyuday Godhasara 			pr_err("Found as already registered\n");
88*c7fdb240SAbhyuday Godhasara 			return -EINVAL;
89*c7fdb240SAbhyuday Godhasara 		}
90*c7fdb240SAbhyuday Godhasara 	}
91*c7fdb240SAbhyuday Godhasara 
92*c7fdb240SAbhyuday Godhasara 	/* Add new entry if not present */
93*c7fdb240SAbhyuday Godhasara 	eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
94*c7fdb240SAbhyuday Godhasara 	if (!eve_data)
95*c7fdb240SAbhyuday Godhasara 		return -ENOMEM;
96*c7fdb240SAbhyuday Godhasara 
97*c7fdb240SAbhyuday Godhasara 	eve_data->key = key;
98*c7fdb240SAbhyuday Godhasara 	eve_data->cb_type = PM_NOTIFY_CB;
99*c7fdb240SAbhyuday Godhasara 	eve_data->eve_cb = cb_fun;
100*c7fdb240SAbhyuday Godhasara 	eve_data->wake = wake;
101*c7fdb240SAbhyuday Godhasara 	eve_data->agent_data = data;
102*c7fdb240SAbhyuday Godhasara 
103*c7fdb240SAbhyuday Godhasara 	hash_add(reg_driver_map, &eve_data->hentry, key);
104*c7fdb240SAbhyuday Godhasara 
105*c7fdb240SAbhyuday Godhasara 	return 0;
106*c7fdb240SAbhyuday Godhasara }
107*c7fdb240SAbhyuday Godhasara 
108*c7fdb240SAbhyuday Godhasara static int xlnx_add_cb_for_suspend(event_cb_func_t cb_fun, void *data)
109*c7fdb240SAbhyuday Godhasara {
110*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
111*c7fdb240SAbhyuday Godhasara 
112*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given cb_type */
113*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
114*c7fdb240SAbhyuday Godhasara 		if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
115*c7fdb240SAbhyuday Godhasara 			pr_err("Found as already registered\n");
116*c7fdb240SAbhyuday Godhasara 			return -EINVAL;
117*c7fdb240SAbhyuday Godhasara 		}
118*c7fdb240SAbhyuday Godhasara 	}
119*c7fdb240SAbhyuday Godhasara 
120*c7fdb240SAbhyuday Godhasara 	/* Add new entry if not present */
121*c7fdb240SAbhyuday Godhasara 	eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
122*c7fdb240SAbhyuday Godhasara 	if (!eve_data)
123*c7fdb240SAbhyuday Godhasara 		return -ENOMEM;
124*c7fdb240SAbhyuday Godhasara 
125*c7fdb240SAbhyuday Godhasara 	eve_data->key = 0;
126*c7fdb240SAbhyuday Godhasara 	eve_data->cb_type = PM_INIT_SUSPEND_CB;
127*c7fdb240SAbhyuday Godhasara 	eve_data->eve_cb = cb_fun;
128*c7fdb240SAbhyuday Godhasara 	eve_data->agent_data = data;
129*c7fdb240SAbhyuday Godhasara 
130*c7fdb240SAbhyuday Godhasara 	hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB);
131*c7fdb240SAbhyuday Godhasara 
132*c7fdb240SAbhyuday Godhasara 	return 0;
133*c7fdb240SAbhyuday Godhasara }
134*c7fdb240SAbhyuday Godhasara 
135*c7fdb240SAbhyuday Godhasara static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
136*c7fdb240SAbhyuday Godhasara {
137*c7fdb240SAbhyuday Godhasara 	bool is_callback_found = false;
138*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
139*c7fdb240SAbhyuday Godhasara 
140*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given cb_type */
141*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
142*c7fdb240SAbhyuday Godhasara 		if (eve_data->cb_type == PM_INIT_SUSPEND_CB &&
143*c7fdb240SAbhyuday Godhasara 		    eve_data->eve_cb == cb_fun) {
144*c7fdb240SAbhyuday Godhasara 			is_callback_found = true;
145*c7fdb240SAbhyuday Godhasara 			/* remove an object from a hashtable */
146*c7fdb240SAbhyuday Godhasara 			hash_del(&eve_data->hentry);
147*c7fdb240SAbhyuday Godhasara 			kfree(eve_data);
148*c7fdb240SAbhyuday Godhasara 		}
149*c7fdb240SAbhyuday Godhasara 	}
150*c7fdb240SAbhyuday Godhasara 	if (!is_callback_found) {
151*c7fdb240SAbhyuday Godhasara 		pr_warn("Didn't find any registered callback for suspend event\n");
152*c7fdb240SAbhyuday Godhasara 		return -EINVAL;
153*c7fdb240SAbhyuday Godhasara 	}
154*c7fdb240SAbhyuday Godhasara 
155*c7fdb240SAbhyuday Godhasara 	return 0;
156*c7fdb240SAbhyuday Godhasara }
157*c7fdb240SAbhyuday Godhasara 
158*c7fdb240SAbhyuday Godhasara static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
159*c7fdb240SAbhyuday Godhasara 					   event_cb_func_t cb_fun)
160*c7fdb240SAbhyuday Godhasara {
161*c7fdb240SAbhyuday Godhasara 	bool is_callback_found = false;
162*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
163*c7fdb240SAbhyuday Godhasara 	u64 key = ((u64)node_id << 32U) | (u64)event;
164*c7fdb240SAbhyuday Godhasara 
165*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given key id */
166*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
167*c7fdb240SAbhyuday Godhasara 		if (eve_data->key == key &&
168*c7fdb240SAbhyuday Godhasara 		    eve_data->eve_cb == cb_fun) {
169*c7fdb240SAbhyuday Godhasara 			is_callback_found = true;
170*c7fdb240SAbhyuday Godhasara 			/* remove an object from a hashtable */
171*c7fdb240SAbhyuday Godhasara 			hash_del(&eve_data->hentry);
172*c7fdb240SAbhyuday Godhasara 			kfree(eve_data);
173*c7fdb240SAbhyuday Godhasara 		}
174*c7fdb240SAbhyuday Godhasara 	}
175*c7fdb240SAbhyuday Godhasara 	if (!is_callback_found) {
176*c7fdb240SAbhyuday Godhasara 		pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
177*c7fdb240SAbhyuday Godhasara 			node_id, event);
178*c7fdb240SAbhyuday Godhasara 		return -EINVAL;
179*c7fdb240SAbhyuday Godhasara 	}
180*c7fdb240SAbhyuday Godhasara 
181*c7fdb240SAbhyuday Godhasara 	return 0;
182*c7fdb240SAbhyuday Godhasara }
183*c7fdb240SAbhyuday Godhasara 
184*c7fdb240SAbhyuday Godhasara /**
185*c7fdb240SAbhyuday Godhasara  * xlnx_register_event() - Register for the event.
186*c7fdb240SAbhyuday Godhasara  * @cb_type:	Type of callback from pm_api_cb_id,
187*c7fdb240SAbhyuday Godhasara  *			PM_NOTIFY_CB - for Error Events,
188*c7fdb240SAbhyuday Godhasara  *			PM_INIT_SUSPEND_CB - for suspend callback.
189*c7fdb240SAbhyuday Godhasara  * @node_id:	Node-Id related to event.
190*c7fdb240SAbhyuday Godhasara  * @event:	Event Mask for the Error Event.
191*c7fdb240SAbhyuday Godhasara  * @wake:	Flag specifying whether the subsystem should be woken upon
192*c7fdb240SAbhyuday Godhasara  *		event notification.
193*c7fdb240SAbhyuday Godhasara  * @cb_fun:	Function pointer to store the callback function.
194*c7fdb240SAbhyuday Godhasara  * @data:	Pointer for the driver instance.
195*c7fdb240SAbhyuday Godhasara  *
196*c7fdb240SAbhyuday Godhasara  * Return:	Returns 0 on successful registration else error code.
197*c7fdb240SAbhyuday Godhasara  */
198*c7fdb240SAbhyuday Godhasara int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
199*c7fdb240SAbhyuday Godhasara 			const bool wake, event_cb_func_t cb_fun, void *data)
200*c7fdb240SAbhyuday Godhasara {
201*c7fdb240SAbhyuday Godhasara 	int ret = 0;
202*c7fdb240SAbhyuday Godhasara 	u32 eve;
203*c7fdb240SAbhyuday Godhasara 	int pos;
204*c7fdb240SAbhyuday Godhasara 
205*c7fdb240SAbhyuday Godhasara 	if (event_manager_availability)
206*c7fdb240SAbhyuday Godhasara 		return event_manager_availability;
207*c7fdb240SAbhyuday Godhasara 
208*c7fdb240SAbhyuday Godhasara 	if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
209*c7fdb240SAbhyuday Godhasara 		pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
210*c7fdb240SAbhyuday Godhasara 		return -EINVAL;
211*c7fdb240SAbhyuday Godhasara 	}
212*c7fdb240SAbhyuday Godhasara 
213*c7fdb240SAbhyuday Godhasara 	if (!cb_fun)
214*c7fdb240SAbhyuday Godhasara 		return -EFAULT;
215*c7fdb240SAbhyuday Godhasara 
216*c7fdb240SAbhyuday Godhasara 	if (cb_type == PM_INIT_SUSPEND_CB) {
217*c7fdb240SAbhyuday Godhasara 		ret = xlnx_add_cb_for_suspend(cb_fun, data);
218*c7fdb240SAbhyuday Godhasara 	} else {
219*c7fdb240SAbhyuday Godhasara 		if (!xlnx_is_error_event(node_id)) {
220*c7fdb240SAbhyuday Godhasara 			/* Add entry for Node-Id/Event in hash table */
221*c7fdb240SAbhyuday Godhasara 			ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data);
222*c7fdb240SAbhyuday Godhasara 		} else {
223*c7fdb240SAbhyuday Godhasara 			/* Add into Hash table */
224*c7fdb240SAbhyuday Godhasara 			for (pos = 0; pos < MAX_BITS; pos++) {
225*c7fdb240SAbhyuday Godhasara 				eve = event & (1 << pos);
226*c7fdb240SAbhyuday Godhasara 				if (!eve)
227*c7fdb240SAbhyuday Godhasara 					continue;
228*c7fdb240SAbhyuday Godhasara 
229*c7fdb240SAbhyuday Godhasara 				/* Add entry for Node-Id/Eve in hash table */
230*c7fdb240SAbhyuday Godhasara 				ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun,
231*c7fdb240SAbhyuday Godhasara 								   data);
232*c7fdb240SAbhyuday Godhasara 				/* Break the loop if got error */
233*c7fdb240SAbhyuday Godhasara 				if (ret)
234*c7fdb240SAbhyuday Godhasara 					break;
235*c7fdb240SAbhyuday Godhasara 			}
236*c7fdb240SAbhyuday Godhasara 			if (ret) {
237*c7fdb240SAbhyuday Godhasara 				/* Skip the Event for which got the error */
238*c7fdb240SAbhyuday Godhasara 				pos--;
239*c7fdb240SAbhyuday Godhasara 				/* Remove registered(during this call) event from hash table */
240*c7fdb240SAbhyuday Godhasara 				for ( ; pos >= 0; pos--) {
241*c7fdb240SAbhyuday Godhasara 					eve = event & (1 << pos);
242*c7fdb240SAbhyuday Godhasara 					if (!eve)
243*c7fdb240SAbhyuday Godhasara 						continue;
244*c7fdb240SAbhyuday Godhasara 					xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
245*c7fdb240SAbhyuday Godhasara 				}
246*c7fdb240SAbhyuday Godhasara 			}
247*c7fdb240SAbhyuday Godhasara 		}
248*c7fdb240SAbhyuday Godhasara 
249*c7fdb240SAbhyuday Godhasara 		if (ret) {
250*c7fdb240SAbhyuday Godhasara 			pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
251*c7fdb240SAbhyuday Godhasara 			       event, ret);
252*c7fdb240SAbhyuday Godhasara 			return ret;
253*c7fdb240SAbhyuday Godhasara 		}
254*c7fdb240SAbhyuday Godhasara 
255*c7fdb240SAbhyuday Godhasara 		/* Register for Node-Id/Event combination in firmware */
256*c7fdb240SAbhyuday Godhasara 		ret = zynqmp_pm_register_notifier(node_id, event, wake, true);
257*c7fdb240SAbhyuday Godhasara 		if (ret) {
258*c7fdb240SAbhyuday Godhasara 			pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
259*c7fdb240SAbhyuday Godhasara 			       event, ret);
260*c7fdb240SAbhyuday Godhasara 			/* Remove already registered event from hash table */
261*c7fdb240SAbhyuday Godhasara 			if (xlnx_is_error_event(node_id)) {
262*c7fdb240SAbhyuday Godhasara 				for (pos = 0; pos < MAX_BITS; pos++) {
263*c7fdb240SAbhyuday Godhasara 					eve = event & (1 << pos);
264*c7fdb240SAbhyuday Godhasara 					if (!eve)
265*c7fdb240SAbhyuday Godhasara 						continue;
266*c7fdb240SAbhyuday Godhasara 					xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
267*c7fdb240SAbhyuday Godhasara 				}
268*c7fdb240SAbhyuday Godhasara 			} else {
269*c7fdb240SAbhyuday Godhasara 				xlnx_remove_cb_for_notify_event(node_id, event, cb_fun);
270*c7fdb240SAbhyuday Godhasara 			}
271*c7fdb240SAbhyuday Godhasara 			return ret;
272*c7fdb240SAbhyuday Godhasara 		}
273*c7fdb240SAbhyuday Godhasara 	}
274*c7fdb240SAbhyuday Godhasara 
275*c7fdb240SAbhyuday Godhasara 	return ret;
276*c7fdb240SAbhyuday Godhasara }
277*c7fdb240SAbhyuday Godhasara EXPORT_SYMBOL_GPL(xlnx_register_event);
278*c7fdb240SAbhyuday Godhasara 
279*c7fdb240SAbhyuday Godhasara /**
280*c7fdb240SAbhyuday Godhasara  * xlnx_unregister_event() - Unregister for the event.
281*c7fdb240SAbhyuday Godhasara  * @cb_type:	Type of callback from pm_api_cb_id,
282*c7fdb240SAbhyuday Godhasara  *			PM_NOTIFY_CB - for Error Events,
283*c7fdb240SAbhyuday Godhasara  *			PM_INIT_SUSPEND_CB - for suspend callback.
284*c7fdb240SAbhyuday Godhasara  * @node_id:	Node-Id related to event.
285*c7fdb240SAbhyuday Godhasara  * @event:	Event Mask for the Error Event.
286*c7fdb240SAbhyuday Godhasara  * @cb_fun:	Function pointer of callback function.
287*c7fdb240SAbhyuday Godhasara  *
288*c7fdb240SAbhyuday Godhasara  * Return:	Returns 0 on successful unregistration else error code.
289*c7fdb240SAbhyuday Godhasara  */
290*c7fdb240SAbhyuday Godhasara int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
291*c7fdb240SAbhyuday Godhasara 			  event_cb_func_t cb_fun)
292*c7fdb240SAbhyuday Godhasara {
293*c7fdb240SAbhyuday Godhasara 	int ret;
294*c7fdb240SAbhyuday Godhasara 	u32 eve, pos;
295*c7fdb240SAbhyuday Godhasara 
296*c7fdb240SAbhyuday Godhasara 	if (event_manager_availability)
297*c7fdb240SAbhyuday Godhasara 		return event_manager_availability;
298*c7fdb240SAbhyuday Godhasara 
299*c7fdb240SAbhyuday Godhasara 	if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
300*c7fdb240SAbhyuday Godhasara 		pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
301*c7fdb240SAbhyuday Godhasara 		return -EINVAL;
302*c7fdb240SAbhyuday Godhasara 	}
303*c7fdb240SAbhyuday Godhasara 
304*c7fdb240SAbhyuday Godhasara 	if (!cb_fun)
305*c7fdb240SAbhyuday Godhasara 		return -EFAULT;
306*c7fdb240SAbhyuday Godhasara 
307*c7fdb240SAbhyuday Godhasara 	if (cb_type == PM_INIT_SUSPEND_CB) {
308*c7fdb240SAbhyuday Godhasara 		ret = xlnx_remove_cb_for_suspend(cb_fun);
309*c7fdb240SAbhyuday Godhasara 	} else {
310*c7fdb240SAbhyuday Godhasara 		/* Remove Node-Id/Event from hash table */
311*c7fdb240SAbhyuday Godhasara 		if (!xlnx_is_error_event(node_id)) {
312*c7fdb240SAbhyuday Godhasara 			xlnx_remove_cb_for_notify_event(node_id, event, cb_fun);
313*c7fdb240SAbhyuday Godhasara 		} else {
314*c7fdb240SAbhyuday Godhasara 			for (pos = 0; pos < MAX_BITS; pos++) {
315*c7fdb240SAbhyuday Godhasara 				eve = event & (1 << pos);
316*c7fdb240SAbhyuday Godhasara 				if (!eve)
317*c7fdb240SAbhyuday Godhasara 					continue;
318*c7fdb240SAbhyuday Godhasara 
319*c7fdb240SAbhyuday Godhasara 				xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
320*c7fdb240SAbhyuday Godhasara 			}
321*c7fdb240SAbhyuday Godhasara 		}
322*c7fdb240SAbhyuday Godhasara 
323*c7fdb240SAbhyuday Godhasara 		/* Un-register for Node-Id/Event combination */
324*c7fdb240SAbhyuday Godhasara 		ret = zynqmp_pm_register_notifier(node_id, event, false, false);
325*c7fdb240SAbhyuday Godhasara 		if (ret) {
326*c7fdb240SAbhyuday Godhasara 			pr_err("%s() failed for 0x%x and 0x%x: %d\n",
327*c7fdb240SAbhyuday Godhasara 			       __func__, node_id, event, ret);
328*c7fdb240SAbhyuday Godhasara 			return ret;
329*c7fdb240SAbhyuday Godhasara 		}
330*c7fdb240SAbhyuday Godhasara 	}
331*c7fdb240SAbhyuday Godhasara 
332*c7fdb240SAbhyuday Godhasara 	return ret;
333*c7fdb240SAbhyuday Godhasara }
334*c7fdb240SAbhyuday Godhasara EXPORT_SYMBOL_GPL(xlnx_unregister_event);
335*c7fdb240SAbhyuday Godhasara 
336*c7fdb240SAbhyuday Godhasara static void xlnx_call_suspend_cb_handler(const u32 *payload)
337*c7fdb240SAbhyuday Godhasara {
338*c7fdb240SAbhyuday Godhasara 	bool is_callback_found = false;
339*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
340*c7fdb240SAbhyuday Godhasara 	u32 cb_type = payload[0];
341*c7fdb240SAbhyuday Godhasara 
342*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given cb_type */
343*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, cb_type) {
344*c7fdb240SAbhyuday Godhasara 		if (eve_data->cb_type == cb_type) {
345*c7fdb240SAbhyuday Godhasara 			eve_data->eve_cb(&payload[0], eve_data->agent_data);
346*c7fdb240SAbhyuday Godhasara 			is_callback_found = true;
347*c7fdb240SAbhyuday Godhasara 		}
348*c7fdb240SAbhyuday Godhasara 	}
349*c7fdb240SAbhyuday Godhasara 	if (!is_callback_found)
350*c7fdb240SAbhyuday Godhasara 		pr_warn("Didn't find any registered callback for suspend event\n");
351*c7fdb240SAbhyuday Godhasara }
352*c7fdb240SAbhyuday Godhasara 
353*c7fdb240SAbhyuday Godhasara static void xlnx_call_notify_cb_handler(const u32 *payload)
354*c7fdb240SAbhyuday Godhasara {
355*c7fdb240SAbhyuday Godhasara 	bool is_callback_found = false;
356*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
357*c7fdb240SAbhyuday Godhasara 	u64 key = ((u64)payload[1] << 32U) | (u64)payload[2];
358*c7fdb240SAbhyuday Godhasara 	int ret;
359*c7fdb240SAbhyuday Godhasara 
360*c7fdb240SAbhyuday Godhasara 	/* Check for existing entry in hash table for given key id */
361*c7fdb240SAbhyuday Godhasara 	hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
362*c7fdb240SAbhyuday Godhasara 		if (eve_data->key == key) {
363*c7fdb240SAbhyuday Godhasara 			eve_data->eve_cb(&payload[0], eve_data->agent_data);
364*c7fdb240SAbhyuday Godhasara 			is_callback_found = true;
365*c7fdb240SAbhyuday Godhasara 
366*c7fdb240SAbhyuday Godhasara 			/* re register with firmware to get future events */
367*c7fdb240SAbhyuday Godhasara 			ret = zynqmp_pm_register_notifier(payload[1], payload[2],
368*c7fdb240SAbhyuday Godhasara 							  eve_data->wake, true);
369*c7fdb240SAbhyuday Godhasara 			if (ret) {
370*c7fdb240SAbhyuday Godhasara 				pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__,
371*c7fdb240SAbhyuday Godhasara 				       payload[1], payload[2], ret);
372*c7fdb240SAbhyuday Godhasara 				/* Remove already registered event from hash table */
373*c7fdb240SAbhyuday Godhasara 				xlnx_remove_cb_for_notify_event(payload[1], payload[2],
374*c7fdb240SAbhyuday Godhasara 								eve_data->eve_cb);
375*c7fdb240SAbhyuday Godhasara 			}
376*c7fdb240SAbhyuday Godhasara 		}
377*c7fdb240SAbhyuday Godhasara 	}
378*c7fdb240SAbhyuday Godhasara 	if (!is_callback_found)
379*c7fdb240SAbhyuday Godhasara 		pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
380*c7fdb240SAbhyuday Godhasara 			payload[1], payload[2]);
381*c7fdb240SAbhyuday Godhasara }
382*c7fdb240SAbhyuday Godhasara 
383*c7fdb240SAbhyuday Godhasara static void xlnx_get_event_callback_data(u32 *buf)
384*c7fdb240SAbhyuday Godhasara {
385*c7fdb240SAbhyuday Godhasara 	zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
386*c7fdb240SAbhyuday Godhasara }
387*c7fdb240SAbhyuday Godhasara 
388*c7fdb240SAbhyuday Godhasara static irqreturn_t xlnx_event_handler(int irq, void *dev_id)
389*c7fdb240SAbhyuday Godhasara {
390*c7fdb240SAbhyuday Godhasara 	u32 cb_type, node_id, event, pos;
391*c7fdb240SAbhyuday Godhasara 	u32 payload[CB_MAX_PAYLOAD_SIZE] = {0};
392*c7fdb240SAbhyuday Godhasara 	u32 event_data[CB_MAX_PAYLOAD_SIZE] = {0};
393*c7fdb240SAbhyuday Godhasara 
394*c7fdb240SAbhyuday Godhasara 	/* Get event data */
395*c7fdb240SAbhyuday Godhasara 	xlnx_get_event_callback_data(payload);
396*c7fdb240SAbhyuday Godhasara 
397*c7fdb240SAbhyuday Godhasara 	/* First element is callback type, others are callback arguments */
398*c7fdb240SAbhyuday Godhasara 	cb_type = payload[0];
399*c7fdb240SAbhyuday Godhasara 
400*c7fdb240SAbhyuday Godhasara 	if (cb_type == PM_NOTIFY_CB) {
401*c7fdb240SAbhyuday Godhasara 		node_id = payload[1];
402*c7fdb240SAbhyuday Godhasara 		event = payload[2];
403*c7fdb240SAbhyuday Godhasara 		if (!xlnx_is_error_event(node_id)) {
404*c7fdb240SAbhyuday Godhasara 			xlnx_call_notify_cb_handler(payload);
405*c7fdb240SAbhyuday Godhasara 		} else {
406*c7fdb240SAbhyuday Godhasara 			/*
407*c7fdb240SAbhyuday Godhasara 			 * Each call back function expecting payload as an input arguments.
408*c7fdb240SAbhyuday Godhasara 			 * We can get multiple error events as in one call back through error
409*c7fdb240SAbhyuday Godhasara 			 * mask. So payload[2] may can contain multiple error events.
410*c7fdb240SAbhyuday Godhasara 			 * In reg_driver_map database we store data in the combination of single
411*c7fdb240SAbhyuday Godhasara 			 * node_id-error combination.
412*c7fdb240SAbhyuday Godhasara 			 * So coping the payload message into event_data and update the
413*c7fdb240SAbhyuday Godhasara 			 * event_data[2] with Error Mask for single error event and use
414*c7fdb240SAbhyuday Godhasara 			 * event_data as input argument for registered call back function.
415*c7fdb240SAbhyuday Godhasara 			 *
416*c7fdb240SAbhyuday Godhasara 			 */
417*c7fdb240SAbhyuday Godhasara 			memcpy(event_data, payload, (4 * CB_MAX_PAYLOAD_SIZE));
418*c7fdb240SAbhyuday Godhasara 			/* Support Multiple Error Event */
419*c7fdb240SAbhyuday Godhasara 			for (pos = 0; pos < MAX_BITS; pos++) {
420*c7fdb240SAbhyuday Godhasara 				if ((0 == (event & (1 << pos))))
421*c7fdb240SAbhyuday Godhasara 					continue;
422*c7fdb240SAbhyuday Godhasara 				event_data[2] = (event & (1 << pos));
423*c7fdb240SAbhyuday Godhasara 				xlnx_call_notify_cb_handler(event_data);
424*c7fdb240SAbhyuday Godhasara 			}
425*c7fdb240SAbhyuday Godhasara 		}
426*c7fdb240SAbhyuday Godhasara 	} else if (cb_type == PM_INIT_SUSPEND_CB) {
427*c7fdb240SAbhyuday Godhasara 		xlnx_call_suspend_cb_handler(payload);
428*c7fdb240SAbhyuday Godhasara 	} else {
429*c7fdb240SAbhyuday Godhasara 		pr_err("%s() Unsupported Callback %d\n", __func__, cb_type);
430*c7fdb240SAbhyuday Godhasara 	}
431*c7fdb240SAbhyuday Godhasara 
432*c7fdb240SAbhyuday Godhasara 	return IRQ_HANDLED;
433*c7fdb240SAbhyuday Godhasara }
434*c7fdb240SAbhyuday Godhasara 
435*c7fdb240SAbhyuday Godhasara static int xlnx_event_cpuhp_start(unsigned int cpu)
436*c7fdb240SAbhyuday Godhasara {
437*c7fdb240SAbhyuday Godhasara 	enable_percpu_irq(virq_sgi, IRQ_TYPE_NONE);
438*c7fdb240SAbhyuday Godhasara 
439*c7fdb240SAbhyuday Godhasara 	return 0;
440*c7fdb240SAbhyuday Godhasara }
441*c7fdb240SAbhyuday Godhasara 
442*c7fdb240SAbhyuday Godhasara static int xlnx_event_cpuhp_down(unsigned int cpu)
443*c7fdb240SAbhyuday Godhasara {
444*c7fdb240SAbhyuday Godhasara 	disable_percpu_irq(virq_sgi);
445*c7fdb240SAbhyuday Godhasara 
446*c7fdb240SAbhyuday Godhasara 	return 0;
447*c7fdb240SAbhyuday Godhasara }
448*c7fdb240SAbhyuday Godhasara 
449*c7fdb240SAbhyuday Godhasara static void xlnx_disable_percpu_irq(void *data)
450*c7fdb240SAbhyuday Godhasara {
451*c7fdb240SAbhyuday Godhasara 	disable_percpu_irq(virq_sgi);
452*c7fdb240SAbhyuday Godhasara }
453*c7fdb240SAbhyuday Godhasara 
454*c7fdb240SAbhyuday Godhasara static int xlnx_event_init_sgi(struct platform_device *pdev)
455*c7fdb240SAbhyuday Godhasara {
456*c7fdb240SAbhyuday Godhasara 	int ret = 0;
457*c7fdb240SAbhyuday Godhasara 	int cpu = smp_processor_id();
458*c7fdb240SAbhyuday Godhasara 	/*
459*c7fdb240SAbhyuday Godhasara 	 * IRQ related structures are used for the following:
460*c7fdb240SAbhyuday Godhasara 	 * for each SGI interrupt ensure its mapped by GIC IRQ domain
461*c7fdb240SAbhyuday Godhasara 	 * and that each corresponding linux IRQ for the HW IRQ has
462*c7fdb240SAbhyuday Godhasara 	 * a handler for when receiving an interrupt from the remote
463*c7fdb240SAbhyuday Godhasara 	 * processor.
464*c7fdb240SAbhyuday Godhasara 	 */
465*c7fdb240SAbhyuday Godhasara 	struct irq_domain *domain;
466*c7fdb240SAbhyuday Godhasara 	struct irq_fwspec sgi_fwspec;
467*c7fdb240SAbhyuday Godhasara 	struct device_node *interrupt_parent = NULL;
468*c7fdb240SAbhyuday Godhasara 	struct device *parent = pdev->dev.parent;
469*c7fdb240SAbhyuday Godhasara 
470*c7fdb240SAbhyuday Godhasara 	/* Find GIC controller to map SGIs. */
471*c7fdb240SAbhyuday Godhasara 	interrupt_parent = of_irq_find_parent(parent->of_node);
472*c7fdb240SAbhyuday Godhasara 	if (!interrupt_parent) {
473*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n");
474*c7fdb240SAbhyuday Godhasara 		return -EINVAL;
475*c7fdb240SAbhyuday Godhasara 	}
476*c7fdb240SAbhyuday Godhasara 
477*c7fdb240SAbhyuday Godhasara 	/* Each SGI needs to be associated with GIC's IRQ domain. */
478*c7fdb240SAbhyuday Godhasara 	domain = irq_find_host(interrupt_parent);
479*c7fdb240SAbhyuday Godhasara 	of_node_put(interrupt_parent);
480*c7fdb240SAbhyuday Godhasara 
481*c7fdb240SAbhyuday Godhasara 	/* Each mapping needs GIC domain when finding IRQ mapping. */
482*c7fdb240SAbhyuday Godhasara 	sgi_fwspec.fwnode = domain->fwnode;
483*c7fdb240SAbhyuday Godhasara 
484*c7fdb240SAbhyuday Godhasara 	/*
485*c7fdb240SAbhyuday Godhasara 	 * When irq domain looks at mapping each arg is as follows:
486*c7fdb240SAbhyuday Godhasara 	 * 3 args for: interrupt type (SGI), interrupt # (set later), type
487*c7fdb240SAbhyuday Godhasara 	 */
488*c7fdb240SAbhyuday Godhasara 	sgi_fwspec.param_count = 1;
489*c7fdb240SAbhyuday Godhasara 
490*c7fdb240SAbhyuday Godhasara 	/* Set SGI's hwirq */
491*c7fdb240SAbhyuday Godhasara 	sgi_fwspec.param[0] = sgi_num;
492*c7fdb240SAbhyuday Godhasara 	virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec);
493*c7fdb240SAbhyuday Godhasara 
494*c7fdb240SAbhyuday Godhasara 	per_cpu(cpu_number1, cpu) = cpu;
495*c7fdb240SAbhyuday Godhasara 	ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt",
496*c7fdb240SAbhyuday Godhasara 				 &cpu_number1);
497*c7fdb240SAbhyuday Godhasara 	WARN_ON(ret);
498*c7fdb240SAbhyuday Godhasara 	if (ret) {
499*c7fdb240SAbhyuday Godhasara 		irq_dispose_mapping(virq_sgi);
500*c7fdb240SAbhyuday Godhasara 		return ret;
501*c7fdb240SAbhyuday Godhasara 	}
502*c7fdb240SAbhyuday Godhasara 
503*c7fdb240SAbhyuday Godhasara 	irq_to_desc(virq_sgi);
504*c7fdb240SAbhyuday Godhasara 	irq_set_status_flags(virq_sgi, IRQ_PER_CPU);
505*c7fdb240SAbhyuday Godhasara 
506*c7fdb240SAbhyuday Godhasara 	return ret;
507*c7fdb240SAbhyuday Godhasara }
508*c7fdb240SAbhyuday Godhasara 
509*c7fdb240SAbhyuday Godhasara static void xlnx_event_cleanup_sgi(struct platform_device *pdev)
510*c7fdb240SAbhyuday Godhasara {
511*c7fdb240SAbhyuday Godhasara 	int cpu = smp_processor_id();
512*c7fdb240SAbhyuday Godhasara 
513*c7fdb240SAbhyuday Godhasara 	per_cpu(cpu_number1, cpu) = cpu;
514*c7fdb240SAbhyuday Godhasara 
515*c7fdb240SAbhyuday Godhasara 	cpuhp_remove_state(CPUHP_AP_ONLINE_DYN);
516*c7fdb240SAbhyuday Godhasara 
517*c7fdb240SAbhyuday Godhasara 	on_each_cpu(xlnx_disable_percpu_irq, NULL, 1);
518*c7fdb240SAbhyuday Godhasara 
519*c7fdb240SAbhyuday Godhasara 	irq_clear_status_flags(virq_sgi, IRQ_PER_CPU);
520*c7fdb240SAbhyuday Godhasara 	free_percpu_irq(virq_sgi, &cpu_number1);
521*c7fdb240SAbhyuday Godhasara 	irq_dispose_mapping(virq_sgi);
522*c7fdb240SAbhyuday Godhasara }
523*c7fdb240SAbhyuday Godhasara 
524*c7fdb240SAbhyuday Godhasara static int xlnx_event_manager_probe(struct platform_device *pdev)
525*c7fdb240SAbhyuday Godhasara {
526*c7fdb240SAbhyuday Godhasara 	int ret;
527*c7fdb240SAbhyuday Godhasara 
528*c7fdb240SAbhyuday Godhasara 	ret = zynqmp_pm_feature(PM_REGISTER_NOTIFIER);
529*c7fdb240SAbhyuday Godhasara 	if (ret < 0) {
530*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "Feature check failed with %d\n", ret);
531*c7fdb240SAbhyuday Godhasara 		return ret;
532*c7fdb240SAbhyuday Godhasara 	}
533*c7fdb240SAbhyuday Godhasara 
534*c7fdb240SAbhyuday Godhasara 	if ((ret & FIRMWARE_VERSION_MASK) <
535*c7fdb240SAbhyuday Godhasara 	    REGISTER_NOTIFIER_FIRMWARE_VERSION) {
536*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n",
537*c7fdb240SAbhyuday Godhasara 			REGISTER_NOTIFIER_FIRMWARE_VERSION,
538*c7fdb240SAbhyuday Godhasara 			ret & FIRMWARE_VERSION_MASK);
539*c7fdb240SAbhyuday Godhasara 		return -EOPNOTSUPP;
540*c7fdb240SAbhyuday Godhasara 	}
541*c7fdb240SAbhyuday Godhasara 
542*c7fdb240SAbhyuday Godhasara 	/* Initialize the SGI */
543*c7fdb240SAbhyuday Godhasara 	ret = xlnx_event_init_sgi(pdev);
544*c7fdb240SAbhyuday Godhasara 	if (ret) {
545*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret);
546*c7fdb240SAbhyuday Godhasara 		return ret;
547*c7fdb240SAbhyuday Godhasara 	}
548*c7fdb240SAbhyuday Godhasara 
549*c7fdb240SAbhyuday Godhasara 	/* Setup function for the CPU hot-plug cases */
550*c7fdb240SAbhyuday Godhasara 	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/event:starting",
551*c7fdb240SAbhyuday Godhasara 			  xlnx_event_cpuhp_start, xlnx_event_cpuhp_down);
552*c7fdb240SAbhyuday Godhasara 
553*c7fdb240SAbhyuday Godhasara 	ret = zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num,
554*c7fdb240SAbhyuday Godhasara 				  0, NULL);
555*c7fdb240SAbhyuday Godhasara 	if (ret) {
556*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
557*c7fdb240SAbhyuday Godhasara 		xlnx_event_cleanup_sgi(pdev);
558*c7fdb240SAbhyuday Godhasara 		return ret;
559*c7fdb240SAbhyuday Godhasara 	}
560*c7fdb240SAbhyuday Godhasara 
561*c7fdb240SAbhyuday Godhasara 	event_manager_availability = 0;
562*c7fdb240SAbhyuday Godhasara 
563*c7fdb240SAbhyuday Godhasara 	dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num);
564*c7fdb240SAbhyuday Godhasara 	dev_info(&pdev->dev, "Xilinx Event Management driver probed\n");
565*c7fdb240SAbhyuday Godhasara 
566*c7fdb240SAbhyuday Godhasara 	return ret;
567*c7fdb240SAbhyuday Godhasara }
568*c7fdb240SAbhyuday Godhasara 
569*c7fdb240SAbhyuday Godhasara static int xlnx_event_manager_remove(struct platform_device *pdev)
570*c7fdb240SAbhyuday Godhasara {
571*c7fdb240SAbhyuday Godhasara 	int i;
572*c7fdb240SAbhyuday Godhasara 	struct registered_event_data *eve_data;
573*c7fdb240SAbhyuday Godhasara 	struct hlist_node *tmp;
574*c7fdb240SAbhyuday Godhasara 	int ret;
575*c7fdb240SAbhyuday Godhasara 
576*c7fdb240SAbhyuday Godhasara 	hash_for_each_safe(reg_driver_map, i, tmp, eve_data, hentry) {
577*c7fdb240SAbhyuday Godhasara 		hash_del(&eve_data->hentry);
578*c7fdb240SAbhyuday Godhasara 		kfree(eve_data);
579*c7fdb240SAbhyuday Godhasara 	}
580*c7fdb240SAbhyuday Godhasara 
581*c7fdb240SAbhyuday Godhasara 	ret = zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, 0, 1, NULL);
582*c7fdb240SAbhyuday Godhasara 	if (ret)
583*c7fdb240SAbhyuday Godhasara 		dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret);
584*c7fdb240SAbhyuday Godhasara 
585*c7fdb240SAbhyuday Godhasara 	xlnx_event_cleanup_sgi(pdev);
586*c7fdb240SAbhyuday Godhasara 
587*c7fdb240SAbhyuday Godhasara 	event_manager_availability = -EACCES;
588*c7fdb240SAbhyuday Godhasara 
589*c7fdb240SAbhyuday Godhasara 	return ret;
590*c7fdb240SAbhyuday Godhasara }
591*c7fdb240SAbhyuday Godhasara 
592*c7fdb240SAbhyuday Godhasara static struct platform_driver xlnx_event_manager_driver = {
593*c7fdb240SAbhyuday Godhasara 	.probe = xlnx_event_manager_probe,
594*c7fdb240SAbhyuday Godhasara 	.remove = xlnx_event_manager_remove,
595*c7fdb240SAbhyuday Godhasara 	.driver = {
596*c7fdb240SAbhyuday Godhasara 		.name = "xlnx_event_manager",
597*c7fdb240SAbhyuday Godhasara 	},
598*c7fdb240SAbhyuday Godhasara };
599*c7fdb240SAbhyuday Godhasara module_param(sgi_num, uint, 0);
600*c7fdb240SAbhyuday Godhasara module_platform_driver(xlnx_event_manager_driver);
601