/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_CHIP_H
#define	_CHIP_H

#pragma ident	"@(#)chip.h	1.1	03/09/24 SMI"

/*
 * generic kernel CMT processor support
 */

#ifdef	__cplusplus
extern "C" {
#endif

#if (defined(_KERNEL) || defined(_KMEMUSER))
#include <sys/cpuvar.h>
#include <sys/processor.h>
#include <sys/bitmap.h>
#include <sys/atomic.h>

#define	CHIP_MAX_PCORE	8		/* maximum physical cores per chip */

/*
 * Chip types
 */
typedef enum chip_type {
	CHIP_DEFAULT,			/* Default, non CMT processor */
	CHIP_SMT,			/* SMT, single core */
	CHIP_CMP_SPLIT_CACHE,		/* CMP with split caches */
	CHIP_CMP_SHARED_CACHE,		/* CMP with shared caches */
	CHIP_CMT,			/* Multi-core SMT */
	CHIP_NUM_TYPES
} chip_type_t;

#define	CHIP_IS_MULTICORE(chp)				\
	((chp)->chip_type >= CHIP_CMP_SPLIT_CACHE)


/*
 * Platform's definition of a chip's properties
 */
typedef struct	chip_def {
	chip_type_t		chipd_type;
	int			chipd_rechoose_adj;
} chip_def_t;

/*
 * Per chip kstats
 */
typedef enum chip_stat_types {
	CHIP_ID,		/* chip "id" */
	CHIP_NCPUS,		/* number of active cpus */
	CHIP_LOAD,		/* chip load */
	CHIP_RECHOOSE,		/* chip's rechoose_interval */
	CHIP_NUM_STATS		/* always last */
} chip_stat_t;

#define	CHIP_KSTAT_NAMES		\
static char *chip_kstat_names[] = {	\
					\
	"chip_id",			\
	"logical_cpus",			\
	"chip_load",			\
	"chip_rechoose_interval",	\
}

/*
 * Physical processor (chip) structure.
 */
typedef struct chip {
	chipid_t	chip_id;		/* chip's "id" */
	chipid_t	chip_seqid;		/* sequential id */
	struct chip	*chip_prev;		/* previous chip on list */
	struct chip	*chip_next;		/* next chip on list */
	struct chip	*chip_active_prev;	/* prev chip on active list */
	struct chip	*chip_active_next;	/* next chip on active list */
	chip_type_t	chip_type;		/* type of chip */
	uint32_t	chip_leffect;		/* thread load effect */
	uint16_t	chip_ncpu;		/* number of active cpus */
	uint16_t	chip_ref;		/* chip's reference count */
	struct cpu	*chip_cpus;		/* per chip cpu list */
	int		chip_rechoose_adj;	/* chip specific adjustment */

	/*
	 * chip kstats
	 */
	kstat_t			*chip_kstat;
	kmutex_t		chip_kstat_mutex;
	struct kstat_named	chip_kstat_data[CHIP_NUM_STATS];

	struct chip	*chip_balance;		/* chip to balance against */
	uint32_t	chip_load;		/* chip's load (normalized) */
} chip_t;

/*
 * One thread's effect on a single core chip's load.
 * This value needs to be evenly divisible by
 * all integers between 1 and CHIP_MAX_PCORE.
 * This is necessary to prevent loss of precision when
 * normalizing the chip loads.
 */
#define	CHIP_UNITY_LOAD		840


#ifdef	DEBUG
#define	CHIP_LOAD_INCR(chp) {						\
	int	ld = (chp)->chip_load;					\
	ASSERT(ld + (chp)->chip_leffect > ld);				\
	atomic_add_32(&(chp)->chip_load, (chp)->chip_leffect);		\
}
#else
#define	CHIP_LOAD_INCR(chp)						\
	atomic_add_32(&(chp)->chip_load, (chp)->chip_leffect);
#endif	/* DEBUG */


#define	CHIP_LOAD_DECR(chp) {						\
	ASSERT((chp)->chip_load >= (chp)->chip_leffect);		\
	atomic_add_32(&(chp)->chip_load, -(chp)->chip_leffect);		\
}

/*
 * Sets of chips
 * The "id" used here should be a chip's sequential id.
 * (chip_seqid)
 */
#if defined(_MACHDEP)

#define	CHIP_MAX_CHIPS	NCPU
#define	CHIP_SET_WORDS	BT_BITOUL(CHIP_MAX_CHIPS)

typedef struct chip_set {
	ulong_t csb[CHIP_SET_WORDS];
} chip_set_t;

extern	int	chip_set_isnull(chip_set_t *);

#define	CHIP_SET_ISNULL(set)		chip_set_isnull(&(set))
#define	CHIP_SET_TEST(set, id)		BT_TEST((set).csb, id)
#define	CHIP_SET_REMOVE(set, id)	BT_CLEAR((set).csb, id)
#define	CHIP_SET_ADD(set, id)		BT_SET((set).csb, id)

#define	CHIP_SET_ZERO(set) {			\
	int	_i;				\
	for (_i = 0; _i < CHIP_SET_WORDS; _i++)	\
		(set).csb[_i] = 0;		\
}

#define	CHIP_IN_CPUPART(chp, cp)	\
	(CHIP_SET_TEST((cp)->cp_chipset, (chp)->chip_seqid))

#endif	/* _MACHDEP */

/*
 * Common kernel chip operations
 */
void		chip_cpu_init(cpu_t *);
void		chip_cpu_fini(cpu_t *);
void		chip_cpu_assign(cpu_t *);
void		chip_cpu_unassign(cpu_t *);

void		chip_load_add_capacity(chip_t *);
void		chip_load_remove_capacity(chip_t *);

void		chip_cpu_move_part(cpu_t *, struct cpupart *,
			struct cpupart *);

void		chip_kstat_create(chip_t *);

/*
 * Platform chip operations
 */
chipid_t	chip_plat_get_chipid(cpu_t *);
void		chip_plat_define_chip(cpu_t *, chip_def_t *);

#endif	/* !_KERNEL && !_KMEMUSER */

#ifdef	__cplusplus
}
#endif

#endif /* _CHIP_H */
