コード例 #1
0
ファイル: mdeg.c プロジェクト: apprisi/illumos-gate
void
mdeg_fini(void)
{
	/*
	 * Flip the enabled switch off to make sure that
	 * no events get dispatched while things are being
	 * torn down.
	 */
	mdeg.enabled = B_FALSE;

	/* destroy the task queue */
	taskq_destroy(mdeg.taskq);

	/*
	 * Deallocate the table of registered clients
	 */
	kmem_free(mdeg.tbl, mdeg.maxclnts * sizeof (mdeg_clnt_t));
	rw_destroy(&mdeg.rwlock);

	/*
	 * Free up the cached MDs.
	 */
	if (mdeg.md_curr)
		(void) md_fini_handle(mdeg.md_curr);

	if (mdeg.md_prev)
		(void) md_fini_handle(mdeg.md_prev);

	mutex_destroy(&mdeg.lock);
}
コード例 #2
0
/*
 * General purpose initialization function used to extract parameters
 * from the MD during the boot process. This is called immediately after
 * the in kernel copy of the MD has been initialized so that global
 * flags are available to various subsystems as they get initialized.
 */
static void
init_md_params(void)
{
	md_t		*mdp;
	int		num_nodes;
	mde_cookie_t	*listp;
	int		listsz;

	mdp = md_get_handle();
	ASSERT(mdp);
	num_nodes = md_node_count(mdp);
	ASSERT(num_nodes >= 0);

	listsz = num_nodes * sizeof (mde_cookie_t);
	listp = (mde_cookie_t *)
	    (*curr_mach_descrip_memops->meta_allocp)(listsz);

	/*
	 * Import various parameters from the MD. For now,
	 * the only parameter of interest is whether or not
	 * domaining features are supported.
	 */
	init_domaining_capabilities(mdp, listp);

	(*curr_mach_descrip_memops->meta_freep)(listp, listsz);
	(void) md_fini_handle(mdp);
}
コード例 #3
0
ファイル: mdeg.c プロジェクト: apprisi/illumos-gate
/*
 * Simple algorithm for now, grab the global lock and let all
 * the clients update themselves in parallel. There is a lot of
 * room for improvement here. We could eliminate some scans of
 * the DAG by incrementally scanning at lower levels of the DAG
 * rather than having each client start its own scan from the root.
 */
void
mdeg_notify_clients(void)
{
	md_t		*md_new;
	mdeg_clnt_t	*clnt;
	int		idx;
	int		nclnt;

	rw_enter(&mdeg.rwlock, RW_READER);
	mutex_enter(&mdeg.lock);

	/*
	 * Rotate the MDs
	 */
	if ((md_new = md_get_handle()) == NULL) {
		cmn_err(CE_WARN, "unable to retrieve new MD");
		goto done;
	}

	if (mdeg.md_prev) {
		(void) md_fini_handle(mdeg.md_prev);
	}

	mdeg.md_prev = mdeg.md_curr;
	mdeg.md_curr = md_new;

	if (mdeg.nclnts == 0) {
		MDEG_DBG("mdeg_notify_clients: no clients registered\n");
		goto done;
	}

	/* dispatch the update notification to all clients */
	for (idx = 0, nclnt = 0; idx < mdeg.maxclnts; idx++) {
		clnt = &mdeg.tbl[idx];

		if (!clnt->valid)
			continue;

		MDEG_DBG("notifying client 0x%lx (%d/%d)\n", clnt->hdl,
		    ++nclnt, mdeg.nclnts);

		(void) taskq_dispatch(mdeg.taskq, mdeg_notify_client,
		    (void *)clnt, TQ_SLEEP);
	}

	/*
	 * Wait for all mdeg_notify_client notifications to
	 * finish while we are still holding mdeg.rwlock.
	 */
	taskq_wait(mdeg.taskq);

done:
	mutex_exit(&mdeg.lock);
	rw_exit(&mdeg.rwlock);
}
コード例 #4
0
/*
 * Routine used to setup a newly inserted CPU in preparation for starting
 * it running code.
 */
int
mp_cpu_configure(int cpuid)
{
	md_t		*mdp;
	mde_cookie_t	rootnode, cpunode = MDE_INVAL_ELEM_COOKIE;
	int		listsz, i;
	mde_cookie_t	*listp = NULL;
	int		num_nodes;
	uint64_t	cpuid_prop;
	cpu_t		*cpu;
	processorid_t	id;

	ASSERT(MUTEX_HELD(&cpu_lock));

	if ((mdp = md_get_handle()) == NULL)
		return (ENODEV);

	rootnode = md_root_node(mdp);

	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);

	num_nodes = md_node_count(mdp);

	ASSERT(num_nodes > 0);

	listsz = num_nodes * sizeof (mde_cookie_t);
	listp = kmem_zalloc(listsz, KM_SLEEP);

	num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
	    md_find_name(mdp, "fwd"), listp);

	if (num_nodes < 0)
		return (ENODEV);

	for (i = 0; i < num_nodes; i++) {
		if (md_get_prop_val(mdp, listp[i], "id", &cpuid_prop))
			break;
		if (cpuid_prop == (uint64_t)cpuid) {
			cpunode = listp[i];
			break;
		}
	}

	if (cpunode == MDE_INVAL_ELEM_COOKIE)
		return (ENODEV);

	kmem_free(listp, listsz);

	mpo_cpu_add(mdp, cpuid);

	/*
	 * Note: uses cpu_lock to protect cpunodes
	 * which will be modified inside of fill_cpu and
	 * setup_exec_unit_mappings.
	 */
	fill_cpu(mdp, cpunode);

	/*
	 * Adding a CPU may cause the execution unit sharing
	 * relationships to change. Update the mappings in
	 * the cpunode structures.
	 */
	setup_chip_mappings(mdp);
	setup_exec_unit_mappings(mdp);

	/* propagate the updated mappings to the CPU structures */
	for (id = 0; id < NCPU; id++) {
		if ((cpu = cpu_get(id)) == NULL)
			continue;

		cpu_map_exec_units(cpu);
	}

	(void) md_fini_handle(mdp);

	if ((i = setup_cpu_common(cpuid)) != 0) {
		(void) cleanup_cpu_common(cpuid);
		return (i);
	}

	return (0);
}
コード例 #5
0
ファイル: cnex.c プロジェクト: MatiasNAmendola/AuroraUX-SunOS
/*
 * Exported interface to register a LDC endpoint with
 * the channel nexus
 */
static int
cnex_reg_chan(dev_info_t *dip, uint64_t id, ldc_dev_t devclass)
{
	int		idx;
	cnex_ldc_t	*cldcp;
	cnex_ldc_t	*new_cldcp;
	int		listsz, num_nodes, num_channels;
	md_t		*mdp = NULL;
	mde_cookie_t	rootnode, *listp = NULL;
	uint64_t	tmp_id;
	uint64_t	rxino = (uint64_t)-1;
	uint64_t	txino = (uint64_t)-1;
	cnex_soft_state_t *cnex_ssp;
	int		status, instance;
	dev_info_t	*chan_dip = NULL;

	/* Get device instance and structure */
	instance = ddi_get_instance(dip);
	cnex_ssp = ddi_get_soft_state(cnex_state, instance);

	/* Check to see if channel is already registered */
	mutex_enter(&cnex_ssp->clist_lock);
	cldcp = cnex_ssp->clist;
	while (cldcp) {
		if (cldcp->id == id) {
			DWARN("cnex_reg_chan: channel 0x%llx exists\n", id);
			mutex_exit(&cnex_ssp->clist_lock);
			return (EINVAL);
		}
		cldcp = cldcp->next;
	}
	mutex_exit(&cnex_ssp->clist_lock);

	/* Get the Tx/Rx inos from the MD */
	if ((mdp = md_get_handle()) == NULL) {
		DWARN("cnex_reg_chan: cannot init MD\n");
		return (ENXIO);
	}
	num_nodes = md_node_count(mdp);
	ASSERT(num_nodes > 0);

	listsz = num_nodes * sizeof (mde_cookie_t);
	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);

	rootnode = md_root_node(mdp);

	/* search for all channel_endpoint nodes */
	num_channels = md_scan_dag(mdp, rootnode,
	    md_find_name(mdp, "channel-endpoint"),
	    md_find_name(mdp, "fwd"), listp);
	if (num_channels <= 0) {
		DWARN("cnex_reg_chan: invalid channel id\n");
		kmem_free(listp, listsz);
		(void) md_fini_handle(mdp);
		return (EINVAL);
	}

	for (idx = 0; idx < num_channels; idx++) {

		/* Get the channel ID */
		status = md_get_prop_val(mdp, listp[idx], "id", &tmp_id);
		if (status) {
			DWARN("cnex_reg_chan: cannot read LDC ID\n");
			kmem_free(listp, listsz);
			(void) md_fini_handle(mdp);
			return (ENXIO);
		}
		if (tmp_id != id)
			continue;

		/* Get the Tx and Rx ino */
		status = md_get_prop_val(mdp, listp[idx], "tx-ino", &txino);
		if (status) {
			DWARN("cnex_reg_chan: cannot read Tx ino\n");
			kmem_free(listp, listsz);
			(void) md_fini_handle(mdp);
			return (ENXIO);
		}
		status = md_get_prop_val(mdp, listp[idx], "rx-ino", &rxino);
		if (status) {
			DWARN("cnex_reg_chan: cannot read Rx ino\n");
			kmem_free(listp, listsz);
			(void) md_fini_handle(mdp);
			return (ENXIO);
		}
		chan_dip = cnex_find_chan_dip(dip, id, mdp, listp[idx]);
		ASSERT(chan_dip != NULL);
	}
	kmem_free(listp, listsz);
	(void) md_fini_handle(mdp);

	/*
	 * check to see if we looped through the list of channel IDs without
	 * matching one (i.e. an 'ino' has not been initialised).
	 */
	if ((rxino == -1) || (txino == -1)) {
		DERR("cnex_reg_chan: no ID matching '%llx' in MD\n", id);
		return (ENOENT);
	}

	/* Allocate a new channel structure */
	new_cldcp = kmem_zalloc(sizeof (*new_cldcp), KM_SLEEP);

	/* Initialize the channel */
	mutex_init(&new_cldcp->lock, NULL, MUTEX_DRIVER, NULL);

	new_cldcp->id = id;
	new_cldcp->tx.ino = txino;
	new_cldcp->rx.ino = rxino;
	new_cldcp->devclass = devclass;
	new_cldcp->tx.weight = CNEX_TX_INTR_WEIGHT;
	new_cldcp->rx.weight = cnex_class_weight(devclass);
	new_cldcp->dip = chan_dip;

	/*
	 * Add channel to nexus channel list.
	 * Check again to see if channel is already registered since
	 * clist_lock was dropped above.
	 */
	mutex_enter(&cnex_ssp->clist_lock);
	cldcp = cnex_ssp->clist;
	while (cldcp) {
		if (cldcp->id == id) {
			DWARN("cnex_reg_chan: channel 0x%llx exists\n", id);
			mutex_exit(&cnex_ssp->clist_lock);
			mutex_destroy(&new_cldcp->lock);
			kmem_free(new_cldcp, sizeof (*new_cldcp));
			return (EINVAL);
		}
		cldcp = cldcp->next;
	}
	new_cldcp->next = cnex_ssp->clist;
	cnex_ssp->clist = new_cldcp;
	mutex_exit(&cnex_ssp->clist_lock);

	return (0);
}
コード例 #6
0
ファイル: suspend.c プロジェクト: apprisi/illumos-gate
/*
 * Obtain an updated MD from the hypervisor and update cpunodes, CPU HW
 * sharing data structures, and processor groups.
 */
static void
update_cpu_mappings(void)
{
	md_t		*mdp;
	processorid_t	id;
	cpu_t		*cp;
	cpu_pg_t	*pgps[NCPU];

	if ((mdp = md_get_handle()) == NULL) {
		DBG("suspend: md_get_handle failed");
		return;
	}

	DBG("suspend: updating CPU mappings");

	mutex_enter(&cpu_lock);

	setup_chip_mappings(mdp);
	setup_exec_unit_mappings(mdp);
	for (id = 0; id < NCPU; id++) {
		if ((cp = cpu_get(id)) == NULL)
			continue;
		cpu_map_exec_units(cp);
	}

	/*
	 * Re-calculate processor groups.
	 *
	 * First tear down all PG information before adding any new PG
	 * information derived from the MD we just downloaded. We must
	 * call pg_cpu_inactive and pg_cpu_active with CPUs paused and
	 * we want to minimize the number of times pause_cpus is called.
	 * Inactivating all CPUs would leave PGs without any active CPUs,
	 * so while CPUs are paused, call pg_cpu_inactive and swap in the
	 * bootstrap PG structure saving the original PG structure to be
	 * fini'd afterwards. This prevents the dispatcher from encountering
	 * PGs in which all CPUs are inactive. Offline CPUs are already
	 * inactive in their PGs and shouldn't be reactivated, so we must
	 * not call pg_cpu_inactive or pg_cpu_active for those CPUs.
	 */
	pause_cpus(NULL);
	for (id = 0; id < NCPU; id++) {
		if ((cp = cpu_get(id)) == NULL)
			continue;
		if ((cp->cpu_flags & CPU_OFFLINE) == 0)
			pg_cpu_inactive(cp);
		pgps[id] = cp->cpu_pg;
		pg_cpu_bootstrap(cp);
	}
	start_cpus();

	/*
	 * pg_cpu_fini* and pg_cpu_init* must be called while CPUs are
	 * not paused. Use two separate loops here so that we do not
	 * initialize PG data for CPUs until all the old PG data structures
	 * are torn down.
	 */
	for (id = 0; id < NCPU; id++) {
		if ((cp = cpu_get(id)) == NULL)
			continue;
		pg_cpu_fini(cp, pgps[id]);
		mpo_cpu_remove(id);
	}

	/*
	 * Initialize PG data for each CPU, but leave the bootstrapped
	 * PG structure in place to avoid running with any PGs containing
	 * nothing but inactive CPUs.
	 */
	for (id = 0; id < NCPU; id++) {
		if ((cp = cpu_get(id)) == NULL)
			continue;
		mpo_cpu_add(mdp, id);
		pgps[id] = pg_cpu_init(cp, B_TRUE);
	}

	/*
	 * Now that PG data has been initialized for all CPUs in the
	 * system, replace the bootstrapped PG structure with the
	 * initialized PG structure and call pg_cpu_active for each CPU.
	 */
	pause_cpus(NULL);
	for (id = 0; id < NCPU; id++) {
		if ((cp = cpu_get(id)) == NULL)
			continue;
		cp->cpu_pg = pgps[id];
		if ((cp->cpu_flags & CPU_OFFLINE) == 0)
			pg_cpu_active(cp);
	}
	start_cpus();

	mutex_exit(&cpu_lock);

	(void) md_fini_handle(mdp);
}
コード例 #7
0
ファイル: mdeg.c プロジェクト: apprisi/illumos-gate
/*
 * Send a notification to a client immediately after it registers.
 * The result_t is a list of all the nodes that match their specified
 * nodes of interest, all returned on the added list. This serves
 * as a base of reference to the client. All future MD updates are
 * relative to this list.
 */
static int
mdeg_notify_client_reg(mdeg_clnt_t *clnt)
{
	md_t			*mdp = NULL;
	mde_str_cookie_t	nname;
	mde_str_cookie_t	aname;
	mde_cookie_t		startnode;
	int			nnodes;
	int			nodechk;
	mde_cookie_t		*listp = NULL;
	mdeg_result_t		*mdeg_res = NULL;
	int			rv = MDEG_SUCCESS;

	mutex_enter(&mdeg.lock);

	/*
	 * Handle the special case where the node specification
	 * is NULL. In this case, call the client callback without
	 * any results. All processing is left to the client.
	 */
	if (clnt->pspec == NULL) {
		/* call the client callback */
		(*clnt->cb)(clnt->cb_arg, NULL);
		goto done;
	}

	if ((mdp = md_get_handle()) == NULL) {
		cmn_err(CE_WARN, "unable to retrieve current MD");
		rv = MDEG_FAILURE;
		goto done;
	}

	startnode = mdeg_find_start_node(mdp, clnt->pspec);
	if (startnode == MDE_INVAL_ELEM_COOKIE) {
		/* not much we can do */
		cmn_err(CE_WARN, "unable to match node specifier");
		rv = MDEG_FAILURE;
		goto done;
	}

	/*
	 * Use zalloc to provide correct default values for the
	 * unused removed, match_prev, and match_curr lists.
	 */
	mdeg_res = kmem_zalloc(sizeof (mdeg_result_t), KM_SLEEP);

	nname = md_find_name(mdp, clnt->nmatch->namep);
	aname = md_find_name(mdp, "fwd");

	nnodes = md_scan_dag(mdp, startnode, nname, aname, NULL);

	if (nnodes == 0) {
		MDEG_DBG("mdeg_notify_client_reg: no nodes of interest\n");
		rv = MDEG_SUCCESS;
		goto done;
	} else if (nnodes == -1) {
		MDEG_DBG("error scanning DAG\n");
		rv = MDEG_FAILURE;
		goto done;
	}

	MDEG_DBG("mdeg_notify_client_reg: %d node%s of interest\n",
	    nnodes, (nnodes == 1) ? "" : "s");

	/* get the list of nodes of interest */
	listp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP);
	nodechk = md_scan_dag(mdp, startnode, nname, aname, listp);

	ASSERT(nodechk == nnodes);

	mdeg_res->added.mdp = mdp;
	mdeg_res->added.mdep = listp;
	mdeg_res->added.nelem = nnodes;

	/* call the client callback */
	(*clnt->cb)(clnt->cb_arg, mdeg_res);

done:
	mutex_exit(&mdeg.lock);

	if (mdp)
		(void) md_fini_handle(mdp);

	if (listp)
		kmem_free(listp, sizeof (mde_cookie_t) * nnodes);

	if (mdeg_res)
		kmem_free(mdeg_res, sizeof (mdeg_result_t));

	return (rv);
}