1 /*
2  * mgr.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Implementation of Manager interface to the device object at the
7  * driver level. This queries the NDB data base and retrieves the
8  * data about Node and Processor.
9  *
10  * Copyright (C) 2005-2006 Texas Instruments, Inc.
11  *
12  * This package is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  *
16  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #include <linux/types.h>
22 
23 /*  ----------------------------------- Host OS */
24 #include <dspbridge/host_os.h>
25 
26 /*  ----------------------------------- DSP/BIOS Bridge */
27 #include <dspbridge/dbdefs.h>
28 
29 /*  ----------------------------------- Trace & Debug */
30 #include <dspbridge/dbc.h>
31 
32 /*  ----------------------------------- OS Adaptation Layer */
33 #include <dspbridge/sync.h>
34 
35 /*  ----------------------------------- Others */
36 #include <dspbridge/dbdcd.h>
37 #include <dspbridge/drv.h>
38 #include <dspbridge/dev.h>
39 
40 /*  ----------------------------------- This */
41 #include <dspbridge/mgr.h>
42 
43 /*  ----------------------------------- Defines, Data Structures, Typedefs */
44 #define ZLDLLNAME               ""
45 
46 struct mgr_object {
47 	struct dcd_manager *dcd_mgr;	/* Proc/Node data manager */
48 };
49 
50 /*  ----------------------------------- Globals */
51 static u32 refs;
52 
53 /*
54  *  ========= mgr_create =========
55  *  Purpose:
56  *      MGR Object gets created only once during driver Loading.
57  */
mgr_create(struct mgr_object ** mgr_obj,struct cfg_devnode * dev_node_obj)58 int mgr_create(struct mgr_object **mgr_obj,
59 		      struct cfg_devnode *dev_node_obj)
60 {
61 	int status = 0;
62 	struct mgr_object *pmgr_obj = NULL;
63 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
64 
65 	DBC_REQUIRE(mgr_obj != NULL);
66 	DBC_REQUIRE(refs > 0);
67 
68 	pmgr_obj = kzalloc(sizeof(struct mgr_object), GFP_KERNEL);
69 	if (pmgr_obj) {
70 		status = dcd_create_manager(ZLDLLNAME, &pmgr_obj->dcd_mgr);
71 		if (!status) {
72 			/* If succeeded store the handle in the MGR Object */
73 			if (drv_datap) {
74 				drv_datap->mgr_object = (void *)pmgr_obj;
75 			} else {
76 				status = -EPERM;
77 				pr_err("%s: Failed to store MGR object\n",
78 								__func__);
79 			}
80 
81 			if (!status) {
82 				*mgr_obj = pmgr_obj;
83 			} else {
84 				dcd_destroy_manager(pmgr_obj->dcd_mgr);
85 				kfree(pmgr_obj);
86 			}
87 		} else {
88 			/* failed to Create DCD Manager */
89 			kfree(pmgr_obj);
90 		}
91 	} else {
92 		status = -ENOMEM;
93 	}
94 
95 	DBC_ENSURE(status || pmgr_obj);
96 	return status;
97 }
98 
99 /*
100  *  ========= mgr_destroy =========
101  *     This function is invoked during bridge driver unloading.Frees MGR object.
102  */
mgr_destroy(struct mgr_object * hmgr_obj)103 int mgr_destroy(struct mgr_object *hmgr_obj)
104 {
105 	int status = 0;
106 	struct mgr_object *pmgr_obj = (struct mgr_object *)hmgr_obj;
107 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
108 
109 	DBC_REQUIRE(refs > 0);
110 	DBC_REQUIRE(hmgr_obj);
111 
112 	/* Free resources */
113 	if (hmgr_obj->dcd_mgr)
114 		dcd_destroy_manager(hmgr_obj->dcd_mgr);
115 
116 	kfree(pmgr_obj);
117 	/* Update the driver data with NULL for MGR Object */
118 	if (drv_datap) {
119 		drv_datap->mgr_object = NULL;
120 	} else {
121 		status = -EPERM;
122 		pr_err("%s: Failed to store MGR object\n", __func__);
123 	}
124 
125 	return status;
126 }
127 
128 /*
129  *  ======== mgr_enum_node_info ========
130  *      Enumerate and get configuration information about nodes configured
131  *      in the node database.
132  */
mgr_enum_node_info(u32 node_id,struct dsp_ndbprops * pndb_props,u32 undb_props_size,u32 * pu_num_nodes)133 int mgr_enum_node_info(u32 node_id, struct dsp_ndbprops *pndb_props,
134 			      u32 undb_props_size, u32 *pu_num_nodes)
135 {
136 	int status = 0;
137 	struct dsp_uuid node_uuid;
138 	u32 node_index = 0;
139 	struct dcd_genericobj gen_obj;
140 	struct mgr_object *pmgr_obj = NULL;
141 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
142 
143 	DBC_REQUIRE(pndb_props != NULL);
144 	DBC_REQUIRE(pu_num_nodes != NULL);
145 	DBC_REQUIRE(undb_props_size >= sizeof(struct dsp_ndbprops));
146 	DBC_REQUIRE(refs > 0);
147 
148 	*pu_num_nodes = 0;
149 	/* Get the Manager Object from the driver data */
150 	if (!drv_datap || !drv_datap->mgr_object) {
151 		pr_err("%s: Failed to retrieve the object handle\n", __func__);
152 		return -ENODATA;
153 	}
154 	pmgr_obj = drv_datap->mgr_object;
155 
156 	DBC_ASSERT(pmgr_obj);
157 	/* Forever loop till we hit failed or no more items in the
158 	 * Enumeration. We will exit the loop other than 0; */
159 	while (!status) {
160 		status = dcd_enumerate_object(node_index++, DSP_DCDNODETYPE,
161 				&node_uuid);
162 		if (status)
163 			break;
164 		*pu_num_nodes = node_index;
165 		if (node_id == (node_index - 1)) {
166 			status = dcd_get_object_def(pmgr_obj->dcd_mgr,
167 					&node_uuid, DSP_DCDNODETYPE, &gen_obj);
168 			if (status)
169 				break;
170 			/* Get the Obj def */
171 			*pndb_props = gen_obj.obj_data.node_obj.ndb_props;
172 		}
173 	}
174 
175 	/* the last status is not 0, but neither an error */
176 	if (status > 0)
177 		status = 0;
178 
179 	return status;
180 }
181 
182 /*
183  *  ======== mgr_enum_processor_info ========
184  *      Enumerate and get configuration information about available
185  *      DSP processors.
186  */
mgr_enum_processor_info(u32 processor_id,struct dsp_processorinfo * processor_info,u32 processor_info_size,u8 * pu_num_procs)187 int mgr_enum_processor_info(u32 processor_id,
188 				   struct dsp_processorinfo *
189 				   processor_info, u32 processor_info_size,
190 				   u8 *pu_num_procs)
191 {
192 	int status = 0;
193 	int status1 = 0;
194 	int status2 = 0;
195 	struct dsp_uuid temp_uuid;
196 	u32 temp_index = 0;
197 	u32 proc_index = 0;
198 	struct dcd_genericobj gen_obj;
199 	struct mgr_object *pmgr_obj = NULL;
200 	struct mgr_processorextinfo *ext_info;
201 	struct dev_object *hdev_obj;
202 	struct drv_object *hdrv_obj;
203 	u8 dev_type;
204 	struct cfg_devnode *dev_node;
205 	struct drv_data *drv_datap = dev_get_drvdata(bridge);
206 	bool proc_detect = false;
207 
208 	DBC_REQUIRE(processor_info != NULL);
209 	DBC_REQUIRE(pu_num_procs != NULL);
210 	DBC_REQUIRE(processor_info_size >= sizeof(struct dsp_processorinfo));
211 	DBC_REQUIRE(refs > 0);
212 
213 	*pu_num_procs = 0;
214 
215 	/* Retrieve the Object handle from the driver data */
216 	if (!drv_datap || !drv_datap->drv_object) {
217 		status = -ENODATA;
218 		pr_err("%s: Failed to retrieve the object handle\n", __func__);
219 	} else {
220 		hdrv_obj = drv_datap->drv_object;
221 	}
222 
223 	if (!status) {
224 		status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
225 		if (!status) {
226 			status = dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
227 			status = dev_get_dev_node(hdev_obj, &dev_node);
228 			if (dev_type != DSP_UNIT)
229 				status = -EPERM;
230 
231 			if (!status)
232 				processor_info->processor_type = DSPTYPE64;
233 		}
234 	}
235 	if (status)
236 		goto func_end;
237 
238 	/* Get The Manager Object from the driver data */
239 	if (drv_datap && drv_datap->mgr_object) {
240 		pmgr_obj = drv_datap->mgr_object;
241 	} else {
242 		dev_dbg(bridge, "%s: Failed to get MGR Object\n", __func__);
243 		goto func_end;
244 	}
245 	DBC_ASSERT(pmgr_obj);
246 	/* Forever loop till we hit no more items in the
247 	 * Enumeration. We will exit the loop other than 0; */
248 	while (status1 == 0) {
249 		status1 = dcd_enumerate_object(temp_index++,
250 					       DSP_DCDPROCESSORTYPE,
251 					       &temp_uuid);
252 		if (status1 != 0)
253 			break;
254 
255 		proc_index++;
256 		/* Get the Object properties to find the Device/Processor
257 		 * Type */
258 		if (proc_detect != false)
259 			continue;
260 
261 		status2 = dcd_get_object_def(pmgr_obj->dcd_mgr,
262 					     (struct dsp_uuid *)&temp_uuid,
263 					     DSP_DCDPROCESSORTYPE, &gen_obj);
264 		if (!status2) {
265 			/* Get the Obj def */
266 			if (processor_info_size <
267 			    sizeof(struct mgr_processorextinfo)) {
268 				*processor_info = gen_obj.obj_data.proc_info;
269 			} else {
270 				/* extended info */
271 				ext_info = (struct mgr_processorextinfo *)
272 				    processor_info;
273 				*ext_info = gen_obj.obj_data.ext_proc_obj;
274 			}
275 			dev_dbg(bridge, "%s: Got proctype  from DCD %x\n",
276 				__func__, processor_info->processor_type);
277 			/* See if we got the needed processor */
278 			if (dev_type == DSP_UNIT) {
279 				if (processor_info->processor_type ==
280 				    DSPPROCTYPE_C64)
281 					proc_detect = true;
282 			} else if (dev_type == IVA_UNIT) {
283 				if (processor_info->processor_type ==
284 				    IVAPROCTYPE_ARM7)
285 					proc_detect = true;
286 			}
287 			/* User applciatiuons aonly check for chip type, so
288 			 * this clumsy overwrite */
289 			processor_info->processor_type = DSPTYPE64;
290 		} else {
291 			dev_dbg(bridge, "%s: Failed to get DCD processor info "
292 				"%x\n", __func__, status2);
293 			status = -EPERM;
294 		}
295 	}
296 	*pu_num_procs = proc_index;
297 	if (proc_detect == false) {
298 		dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use "
299 			"CFG registry\n", __func__);
300 		processor_info->processor_type = DSPTYPE64;
301 	}
302 func_end:
303 	return status;
304 }
305 
306 /*
307  *  ======== mgr_exit ========
308  *      Decrement reference count, and free resources when reference count is
309  *      0.
310  */
mgr_exit(void)311 void mgr_exit(void)
312 {
313 	DBC_REQUIRE(refs > 0);
314 	refs--;
315 	if (refs == 0)
316 		dcd_exit();
317 
318 	DBC_ENSURE(refs >= 0);
319 }
320 
321 /*
322  *  ======== mgr_get_dcd_handle ========
323  *      Retrieves the MGR handle. Accessor Function.
324  */
mgr_get_dcd_handle(struct mgr_object * mgr_handle,u32 * dcd_handle)325 int mgr_get_dcd_handle(struct mgr_object *mgr_handle,
326 			      u32 *dcd_handle)
327 {
328 	int status = -EPERM;
329 	struct mgr_object *pmgr_obj = (struct mgr_object *)mgr_handle;
330 
331 	DBC_REQUIRE(refs > 0);
332 	DBC_REQUIRE(dcd_handle != NULL);
333 
334 	*dcd_handle = (u32) NULL;
335 	if (pmgr_obj) {
336 		*dcd_handle = (u32) pmgr_obj->dcd_mgr;
337 		status = 0;
338 	}
339 	DBC_ENSURE((!status && *dcd_handle != (u32) NULL) ||
340 		   (status && *dcd_handle == (u32) NULL));
341 
342 	return status;
343 }
344 
345 /*
346  *  ======== mgr_init ========
347  *      Initialize MGR's private state, keeping a reference count on each call.
348  */
mgr_init(void)349 bool mgr_init(void)
350 {
351 	bool ret = true;
352 	bool init_dcd = false;
353 
354 	DBC_REQUIRE(refs >= 0);
355 
356 	if (refs == 0) {
357 		init_dcd = dcd_init();	/*  DCD Module */
358 
359 		if (!init_dcd)
360 			ret = false;
361 	}
362 
363 	if (ret)
364 		refs++;
365 
366 	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
367 
368 	return ret;
369 }
370 
371 /*
372  *  ======== mgr_wait_for_bridge_events ========
373  *      Block on any Bridge event(s)
374  */
mgr_wait_for_bridge_events(struct dsp_notification ** anotifications,u32 count,u32 * pu_index,u32 utimeout)375 int mgr_wait_for_bridge_events(struct dsp_notification **anotifications,
376 				      u32 count, u32 *pu_index,
377 				      u32 utimeout)
378 {
379 	int status;
380 	struct sync_object *sync_events[MAX_EVENTS];
381 	u32 i;
382 
383 	DBC_REQUIRE(count < MAX_EVENTS);
384 
385 	for (i = 0; i < count; i++)
386 		sync_events[i] = anotifications[i]->handle;
387 
388 	status = sync_wait_on_multiple_events(sync_events, count, utimeout,
389 					      pu_index);
390 
391 	return status;
392 
393 }
394