summaryrefslogblamecommitdiffstats
path: root/drivers/staging/tidspbridge/rmgr/mgr.c
blob: 54f8580b4424312d6411550093269dbaede758ad (plain) (tree)



















                                                                       

                        
                                                          































                                                                             
                                               




                                                       
                                     








                                                                                
                                                    









































































































































































































































                                                                                
                                                     
                                                  

                            
                                                                      

                              
                                        
 
                                 
                       
                                                       

                           

                                                                          




















































                                                                               
/*
 * mgr.c
 *
 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
 *
 * Implementation of Manager interface to the device object at the
 * driver level. This queries the NDB data base and retrieves the
 * data about Node and Processor.
 *
 * Copyright (C) 2005-2006 Texas Instruments, Inc.
 *
 * This package is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <linux/types.h>

/*  ----------------------------------- DSP/BIOS Bridge */
#include <dspbridge/dbdefs.h>

/*  ----------------------------------- Trace & Debug */
#include <dspbridge/dbc.h>

/*  ----------------------------------- OS Adaptation Layer */
#include <dspbridge/cfg.h>
#include <dspbridge/sync.h>

/*  ----------------------------------- Others */
#include <dspbridge/dbdcd.h>
#include <dspbridge/drv.h>
#include <dspbridge/dev.h>

/*  ----------------------------------- This */
#include <dspbridge/mgr.h>

/*  ----------------------------------- Defines, Data Structures, Typedefs */
#define ZLDLLNAME               ""

struct mgr_object {
	struct dcd_manager *hdcd_mgr;	/* Proc/Node data manager */
};

/*  ----------------------------------- Globals */
static u32 refs;

/*
 *  ========= mgr_create =========
 *  Purpose:
 *      MGR Object gets created only once during driver Loading.
 */
int mgr_create(OUT struct mgr_object **mgr_obj,
		      struct cfg_devnode *dev_node_obj)
{
	int status = 0;
	struct mgr_object *pmgr_obj = NULL;

	DBC_REQUIRE(mgr_obj != NULL);
	DBC_REQUIRE(refs > 0);

	pmgr_obj = kzalloc(sizeof(struct mgr_object), GFP_KERNEL);
	if (pmgr_obj) {
		status = dcd_create_manager(ZLDLLNAME, &pmgr_obj->hdcd_mgr);
		if (DSP_SUCCEEDED(status)) {
			/* If succeeded store the handle in the MGR Object */
			status = cfg_set_object((u32) pmgr_obj, REG_MGR_OBJECT);
			if (DSP_SUCCEEDED(status)) {
				*mgr_obj = pmgr_obj;
			} else {
				dcd_destroy_manager(pmgr_obj->hdcd_mgr);
				kfree(pmgr_obj);
			}
		} else {
			/* failed to Create DCD Manager */
			kfree(pmgr_obj);
		}
	} else {
		status = -ENOMEM;
	}

	DBC_ENSURE(DSP_FAILED(status) || pmgr_obj);
	return status;
}

/*
 *  ========= mgr_destroy =========
 *     This function is invoked during bridge driver unloading.Frees MGR object.
 */
int mgr_destroy(struct mgr_object *hmgr_obj)
{
	int status = 0;
	struct mgr_object *pmgr_obj = (struct mgr_object *)hmgr_obj;

	DBC_REQUIRE(refs > 0);
	DBC_REQUIRE(hmgr_obj);

	/* Free resources */
	if (hmgr_obj->hdcd_mgr)
		dcd_destroy_manager(hmgr_obj->hdcd_mgr);

	kfree(pmgr_obj);
	/* Update the Registry with NULL for MGR Object */
	(void)cfg_set_object(0, REG_MGR_OBJECT);

	return status;
}

/*
 *  ======== mgr_enum_node_info ========
 *      Enumerate and get configuration information about nodes configured
 *      in the node database.
 */
int mgr_enum_node_info(u32 node_id, OUT struct dsp_ndbprops *pndb_props,
			      u32 undb_props_size, OUT u32 *pu_num_nodes)
{
	int status = 0;
	struct dsp_uuid node_uuid, temp_uuid;
	u32 temp_index = 0;
	u32 node_index = 0;
	struct dcd_genericobj gen_obj;
	struct mgr_object *pmgr_obj = NULL;

	DBC_REQUIRE(pndb_props != NULL);
	DBC_REQUIRE(pu_num_nodes != NULL);
	DBC_REQUIRE(undb_props_size >= sizeof(struct dsp_ndbprops));
	DBC_REQUIRE(refs > 0);

	*pu_num_nodes = 0;
	/* Get The Manager Object from the Registry */
	status = cfg_get_object((u32 *) &pmgr_obj, REG_MGR_OBJECT);
	if (DSP_FAILED(status))
		goto func_cont;

	DBC_ASSERT(pmgr_obj);
	/* Forever loop till we hit failed or no more items in the
	 * Enumeration. We will exit the loop other than 0; */
	while (status == 0) {
		status = dcd_enumerate_object(temp_index++, DSP_DCDNODETYPE,
					      &temp_uuid);
		if (status == 0) {
			node_index++;
			if (node_id == (node_index - 1))
				node_uuid = temp_uuid;

		}
	}
	if (DSP_SUCCEEDED(status)) {
		if (node_id > (node_index - 1)) {
			status = -EINVAL;
		} else {
			status = dcd_get_object_def(pmgr_obj->hdcd_mgr,
						    (struct dsp_uuid *)
						    &node_uuid, DSP_DCDNODETYPE,
						    &gen_obj);
			if (DSP_SUCCEEDED(status)) {
				/* Get the Obj def */
				*pndb_props =
				    gen_obj.obj_data.node_obj.ndb_props;
				*pu_num_nodes = node_index;
			}
		}
	}

func_cont:
	DBC_ENSURE((DSP_SUCCEEDED(status) && *pu_num_nodes > 0) ||
		   (DSP_FAILED(status) && *pu_num_nodes == 0));

	return status;
}

/*
 *  ======== mgr_enum_processor_info ========
 *      Enumerate and get configuration information about available
 *      DSP processors.
 */
int mgr_enum_processor_info(u32 processor_id,
				   OUT struct dsp_processorinfo *
				   processor_info, u32 processor_info_size,
				   OUT u8 *pu_num_procs)
{
	int status = 0;
	int status1 = 0;
	int status2 = 0;
	struct dsp_uuid temp_uuid;
	u32 temp_index = 0;
	u32 proc_index = 0;
	struct dcd_genericobj gen_obj;
	struct mgr_object *pmgr_obj = NULL;
	struct mgr_processorextinfo *ext_info;
	struct dev_object *hdev_obj;
	struct drv_object *hdrv_obj;
	u8 dev_type;
	struct cfg_devnode *dev_node;
	bool proc_detect = false;

	DBC_REQUIRE(processor_info != NULL);
	DBC_REQUIRE(pu_num_procs != NULL);
	DBC_REQUIRE(processor_info_size >= sizeof(struct dsp_processorinfo));
	DBC_REQUIRE(refs > 0);

	*pu_num_procs = 0;
	status = cfg_get_object((u32 *) &hdrv_obj, REG_DRV_OBJECT);
	if (DSP_SUCCEEDED(status)) {
		status = drv_get_dev_object(processor_id, hdrv_obj, &hdev_obj);
		if (DSP_SUCCEEDED(status)) {
			status = dev_get_dev_type(hdev_obj, (u8 *) &dev_type);
			status = dev_get_dev_node(hdev_obj, &dev_node);
			if (dev_type != DSP_UNIT)
				status = -EPERM;

			if (DSP_SUCCEEDED(status))
				processor_info->processor_type = DSPTYPE64;
		}
	}
	if (DSP_FAILED(status))
		goto func_end;

	/* Get The Manager Object from the Registry */
	if (DSP_FAILED(cfg_get_object((u32 *) &pmgr_obj, REG_MGR_OBJECT))) {
		dev_dbg(bridge, "%s: Failed to get MGR Object\n", __func__);
		goto func_end;
	}
	DBC_ASSERT(pmgr_obj);
	/* Forever loop till we hit no more items in the
	 * Enumeration. We will exit the loop other than 0; */
	while (status1 == 0) {
		status1 = dcd_enumerate_object(temp_index++,
					       DSP_DCDPROCESSORTYPE,
					       &temp_uuid);
		if (status1 != 0)
			break;

		proc_index++;
		/* Get the Object properties to find the Device/Processor
		 * Type */
		if (proc_detect != false)
			continue;

		status2 = dcd_get_object_def(pmgr_obj->hdcd_mgr,
					     (struct dsp_uuid *)&temp_uuid,
					     DSP_DCDPROCESSORTYPE, &gen_obj);
		if (DSP_SUCCEEDED(status2)) {
			/* Get the Obj def */
			if (processor_info_size <
			    sizeof(struct mgr_processorextinfo)) {
				*processor_info = gen_obj.obj_data.proc_info;
			} else {
				/* extended info */
				ext_info = (struct mgr_processorextinfo *)
				    processor_info;
				*ext_info = gen_obj.obj_data.ext_proc_obj;
			}
			dev_dbg(bridge, "%s: Got proctype  from DCD %x\n",
				__func__, processor_info->processor_type);
			/* See if we got the needed processor */
			if (dev_type == DSP_UNIT) {
				if (processor_info->processor_type ==
				    DSPPROCTYPE_C64)
					proc_detect = true;
			} else if (dev_type == IVA_UNIT) {
				if (processor_info->processor_type ==
				    IVAPROCTYPE_ARM7)
					proc_detect = true;
			}
			/* User applciatiuons aonly check for chip type, so
			 * this clumsy overwrite */
			processor_info->processor_type = DSPTYPE64;
		} else {
			dev_dbg(bridge, "%s: Failed to get DCD processor info "
				"%x\n", __func__, status2);
			status = -EPERM;
		}
	}
	*pu_num_procs = proc_index;
	if (proc_detect == false) {
		dev_dbg(bridge, "%s: Failed to get proc info from DCD, so use "
			"CFG registry\n", __func__);
		processor_info->processor_type = DSPTYPE64;
	}
func_end:
	return status;
}

/*
 *  ======== mgr_exit ========
 *      Decrement reference count, and free resources when reference count is
 *      0.
 */
void mgr_exit(void)
{
	DBC_REQUIRE(refs > 0);
	refs--;
	if (refs == 0)
		dcd_exit();

	DBC_ENSURE(refs >= 0);
}

/*
 *  ======== mgr_get_dcd_handle ========
 *      Retrieves the MGR handle. Accessor Function.
 */
int mgr_get_dcd_handle(struct mgr_object *mgr_handle,
			      OUT u32 *dcd_handle)
{
	int status = -EPERM;
	struct mgr_object *pmgr_obj = (struct mgr_object *)mgr_handle;

	DBC_REQUIRE(refs > 0);
	DBC_REQUIRE(dcd_handle != NULL);

	*dcd_handle = (u32) NULL;
	if (pmgr_obj) {
		*dcd_handle = (u32) pmgr_obj->hdcd_mgr;
		status = 0;
	}
	DBC_ENSURE((DSP_SUCCEEDED(status) && *dcd_handle != (u32) NULL) ||
		   (DSP_FAILED(status) && *dcd_handle == (u32) NULL));

	return status;
}

/*
 *  ======== mgr_init ========
 *      Initialize MGR's private state, keeping a reference count on each call.
 */
bool mgr_init(void)
{
	bool ret = true;
	bool init_dcd = false;

	DBC_REQUIRE(refs >= 0);

	if (refs == 0) {
		init_dcd = dcd_init();	/*  DCD Module */

		if (!init_dcd)
			ret = false;
	}

	if (ret)
		refs++;

	DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs >= 0)));

	return ret;
}

/*
 *  ======== mgr_wait_for_bridge_events ========
 *      Block on any Bridge event(s)
 */
int mgr_wait_for_bridge_events(struct dsp_notification **anotifications,
				      u32 count, OUT u32 *pu_index,
				      u32 utimeout)
{
	int status;
	struct sync_object *sync_events[MAX_EVENTS];
	u32 i;

	DBC_REQUIRE(count < MAX_EVENTS);

	for (i = 0; i < count; i++)
		sync_events[i] = anotifications[i]->handle;

	status = sync_wait_on_multiple_events(sync_events, count, utimeout,
					      pu_index);

	return status;

}