Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / tidspbridge / rmgr / mgr.c
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 *hdcd_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  */
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->hdcd_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->hdcd_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  */
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->hdcd_mgr)
114                 dcd_destroy_manager(hmgr_obj->hdcd_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  */
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, temp_uuid;
138         u32 temp_index = 0;
139         u32 node_index = 0;
140         struct dcd_genericobj gen_obj;
141         struct mgr_object *pmgr_obj = NULL;
142         struct drv_data *drv_datap = dev_get_drvdata(bridge);
143
144         DBC_REQUIRE(pndb_props != NULL);
145         DBC_REQUIRE(pu_num_nodes != NULL);
146         DBC_REQUIRE(undb_props_size >= sizeof(struct dsp_ndbprops));
147         DBC_REQUIRE(refs > 0);
148
149         *pu_num_nodes = 0;
150         /* Get the Manager Object from the driver data */
151         if (!drv_datap || !drv_datap->mgr_object) {
152                 status = -ENODATA;
153                 pr_err("%s: Failed to retrieve the object handle\n", __func__);
154                 goto func_cont;
155         } else {
156                 pmgr_obj = drv_datap->mgr_object;
157         }
158
159         DBC_ASSERT(pmgr_obj);
160         /* Forever loop till we hit failed or no more items in the
161          * Enumeration. We will exit the loop other than 0; */
162         while (status == 0) {
163                 status = dcd_enumerate_object(temp_index++, DSP_DCDNODETYPE,
164                                               &temp_uuid);
165                 if (status == 0) {
166                         node_index++;
167                         if (node_id == (node_index - 1))
168                                 node_uuid = temp_uuid;
169
170                 }
171         }
172         if (!status) {
173                 if (node_id > (node_index - 1)) {
174                         status = -EINVAL;
175                 } else {
176                         status = dcd_get_object_def(pmgr_obj->hdcd_mgr,
177                                                     (struct dsp_uuid *)
178                                                     &node_uuid, DSP_DCDNODETYPE,
179                                                     &gen_obj);
180                         if (!status) {
181                                 /* Get the Obj def */
182                                 *pndb_props =
183                                     gen_obj.obj_data.node_obj.ndb_props;
184                                 *pu_num_nodes = node_index;
185                         }
186                 }
187         }
188
189 func_cont:
190         DBC_ENSURE((!status && *pu_num_nodes > 0) ||
191                    (status && *pu_num_nodes == 0));
192
193         return status;
194 }
195
196 /*
197  *  ======== mgr_enum_processor_info ========
198  *      Enumerate and get configuration information about available
199  *      DSP processors.
200  */
201 int mgr_enum_processor_info(u32 processor_id,
202                                    struct dsp_processorinfo *
203                                    processor_info, u32 processor_info_size,
204                                    u8 *pu_num_procs)
205 {
206         int status = 0;
207         int status1 = 0;
208         int status2 = 0;
209         struct dsp_uuid temp_uuid;
210         u32 temp_index = 0;
211         u32 proc_index = 0;
212         struct dcd_genericobj gen_obj;
213         struct mgr_object *pmgr_obj = NULL;
214         struct mgr_processorextinfo *ext_info;
215         struct dev_object *hdev_obj;
216         struct drv_object *hdrv_obj;
217         u8 dev_type;
218         struct cfg_devnode *dev_node;
219         struct drv_data *drv_datap = dev_get_drvdata(bridge);
220         bool proc_detect = false;
221
222         DBC_REQUIRE(processor_info != NULL);
223         DBC_REQUIRE(pu_num_procs != NULL);
224         DBC_REQUIRE(processor_info_size >= sizeof(struct dsp_processorinfo));
225         DBC_REQUIRE(refs > 0);
226
227         *pu_num_procs = 0;
228
229         /* Retrieve the Object handle from the driver data */
230         if (!drv_datap || !drv_datap->drv_object) {
231                 status = -ENODATA;
232                 pr_err("%s: Failed to retrieve the object handle\n", __func__);
233         } else {
234                 hdrv_obj = drv_datap->drv_object;
235         }
236
237         if (!status) {
238                 status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
239                 if (!status) {
240                         status = dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
241                         status = dev_get_dev_node(hdev_obj, &dev_node);
242                         if (dev_type != DSP_UNIT)
243                                 status = -EPERM;
244
245                         if (!status)
246                                 processor_info->processor_type = DSPTYPE64;
247                 }
248         }
249         if (status)
250                 goto func_end;
251
252         /* Get The Manager Object from the driver data */
253         if (drv_datap && drv_datap->mgr_object) {
254                 pmgr_obj = drv_datap->mgr_object;
255         } else {
256                 dev_dbg(bridge, "%s: Failed to get MGR Object\n", __func__);
257                 goto func_end;
258         }
259         DBC_ASSERT(pmgr_obj);
260         /* Forever loop till we hit no more items in the
261          * Enumeration. We will exit the loop other than 0; */
262         while (status1 == 0) {
263                 status1 = dcd_enumerate_object(temp_index++,
264                                                DSP_DCDPROCESSORTYPE,
265                                                &temp_uuid);
266                 if (status1 != 0)
267                         break;
268
269                 proc_index++;
270                 /* Get the Object properties to find the Device/Processor
271                  * Type */
272                 if (proc_detect != false)
273                         continue;
274
275                 status2 = dcd_get_object_def(pmgr_obj->hdcd_mgr,
276                                              (struct dsp_uuid *)&temp_uuid,
277                                              DSP_DCDPROCESSORTYPE, &gen_obj);
278                 if (!status2) {
279                         /* Get the Obj def */
280                         if (processor_info_size <
281                             sizeof(struct mgr_processorextinfo)) {
282                                 *processor_info = gen_obj.obj_data.proc_info;
283                         } else {
284                                 /* extended info */
285                                 ext_info = (struct mgr_processorextinfo *)
286                                     processor_info;
287                                 *ext_info = gen_obj.obj_data.ext_proc_obj;
288                         }
289                         dev_dbg(bridge, "%s: Got proctype  from DCD %x\n",
290                                 __func__, processor_info->processor_type);
291                         /* See if we got the needed processor */
292                         if (dev_type == DSP_UNIT) {
293                                 if (processor_info->processor_type ==
294                                     DSPPROCTYPE_C64)
295                                         proc_detect = true;
296                         } else if (dev_type == IVA_UNIT) {
297                                 if (processor_info->processor_type ==
298                                     IVAPROCTYPE_ARM7)
299                                         proc_detect = true;
300                         }
301                         /* User applciatiuons aonly check for chip type, so
302                          * this clumsy overwrite */
303                         processor_info->processor_type = DSPTYPE64;
304                 } else {
305                         dev_dbg(bridge, "%s: Failed to get DCD processor info "
306                                 "%x\n", __func__, status2);
307                         status = -EPERM;
308                 }
309         }
310         *pu_num_procs = proc_index;
311         if (proc_detect == false) {
312                 dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use "
313                         "CFG registry\n", __func__);
314                 processor_info->processor_type = DSPTYPE64;
315         }
316 func_end:
317         return status;
318 }
319
320 /*
321  *  ======== mgr_exit ========
322  *      Decrement reference count, and free resources when reference count is
323  *      0.
324  */
325 void mgr_exit(void)
326 {
327         DBC_REQUIRE(refs > 0);
328         refs--;
329         if (refs == 0)
330                 dcd_exit();
331
332         DBC_ENSURE(refs >= 0);
333 }
334
335 /*
336  *  ======== mgr_get_dcd_handle ========
337  *      Retrieves the MGR handle. Accessor Function.
338  */
339 int mgr_get_dcd_handle(struct mgr_object *mgr_handle,
340                               u32 *dcd_handle)
341 {
342         int status = -EPERM;
343         struct mgr_object *pmgr_obj = (struct mgr_object *)mgr_handle;
344
345         DBC_REQUIRE(refs > 0);
346         DBC_REQUIRE(dcd_handle != NULL);
347
348         *dcd_handle = (u32) NULL;
349         if (pmgr_obj) {
350                 *dcd_handle = (u32) pmgr_obj->hdcd_mgr;
351                 status = 0;
352         }
353         DBC_ENSURE((!status && *dcd_handle != (u32) NULL) ||
354                    (status && *dcd_handle == (u32) NULL));
355
356         return status;
357 }
358
359 /*
360  *  ======== mgr_init ========
361  *      Initialize MGR's private state, keeping a reference count on each call.
362  */
363 bool mgr_init(void)
364 {
365         bool ret = true;
366         bool init_dcd = false;
367
368         DBC_REQUIRE(refs >= 0);
369
370         if (refs == 0) {
371                 init_dcd = dcd_init();  /*  DCD Module */
372
373                 if (!init_dcd)
374                         ret = false;
375         }
376
377         if (ret)
378                 refs++;
379
380         DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));
381
382         return ret;
383 }
384
385 /*
386  *  ======== mgr_wait_for_bridge_events ========
387  *      Block on any Bridge event(s)
388  */
389 int mgr_wait_for_bridge_events(struct dsp_notification **anotifications,
390                                       u32 count, u32 *pu_index,
391                                       u32 utimeout)
392 {
393         int status;
394         struct sync_object *sync_events[MAX_EVENTS];
395         u32 i;
396
397         DBC_REQUIRE(count < MAX_EVENTS);
398
399         for (i = 0; i < count; i++)
400                 sync_events[i] = anotifications[i]->handle;
401
402         status = sync_wait_on_multiple_events(sync_events, count, utimeout,
403                                               pu_index);
404
405         return status;
406
407 }