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