/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_MC_OPL_H
#define	_SYS_MC_OPL_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#include <sys/note.h>

#ifdef	DEBUG
#define	MC_LOG	if (oplmc_debug) printf
extern int oplmc_debug;
#else
#define	MC_LOG		_NOTE(CONSTANTCONDITION) if (0) printf
#endif

#define	MC_PATROL_INTERVAL_SEC	10

#define	MC_POLL_EXIT	0x01

/*
 * load/store MAC register
 */
extern uint32_t mc_ldphysio(uint64_t);
extern void mc_stphysio(uint64_t, uint32_t);
#define	LD_MAC_REG(paddr)	mc_ldphysio(paddr)
#define	ST_MAC_REG(paddr, data)	mc_stphysio((paddr), (data))

#define	BANKNUM_PER_SB	8

typedef struct {
	uint32_t cs_num;
	uint32_t cs_status;
	uint32_t cs_avail_hi;
	uint32_t cs_avail_low;
	uint32_t dimm_capa_hi;
	uint32_t dimm_capa_low;
	uint32_t ndimms;
} cs_status_t;

typedef	struct scf_log {
	struct scf_log	*sl_next;
	int		sl_bank;
	uint32_t	sl_err_add;
	uint32_t	sl_err_log;
} scf_log_t;

/*
 * Current max serial number size is 12, but keep enough room
 * to accomodate any future changes.
 *
 * Current max part number size is 18 + 18(Sun's partnumber + FJ's partnumber),
 * but keep enough room to accomodate any future changes.
 */
#define	MCOPL_MAX_DIMMNAME	3
#define	MCOPL_MAX_SERIAL	20
#define	MCOPL_MAX_PARTNUM	44
#define	MCOPL_MAX_SERIALID (MCOPL_MAX_SERIAL + MCOPL_MAX_PARTNUM)

typedef struct mc_dimm_info {
	struct	mc_dimm_info *md_next;
	char	md_dimmname[MCOPL_MAX_DIMMNAME + 1];
	char	md_serial[MCOPL_MAX_SERIAL + 1];
	char	md_partnum[MCOPL_MAX_PARTNUM + 1];
} mc_dimm_info_t;

typedef struct mc_retry_info {
	struct mc_retry_info *ri_next;
#define	RETRY_STATE_PENDING	0
#define	RETRY_STATE_ACTIVE	1
#define	RETRY_STATE_REWRITE	2
	int		   ri_state;
	uint32_t	   ri_addr;
} mc_retry_info_t;

typedef struct mc_opl_state {
	struct mc_opl_state *next;
	dev_info_t *mc_dip;
	uint32_t mc_status;
#define	MC_POLL_RUNNING	0x1
#define	MC_SOFT_SUSPENDED	0x2	/* suspended by DR */
#define	MC_DRIVER_SUSPENDED	0x4	/* DDI_SUSPEND */
#define	MC_MEMORYLESS		0x8
	uint32_t mc_board_num;		/* board# */
	uint32_t mc_phys_board_num;	/* physical board# */
	uint64_t mc_start_address;	/* sb-mem-ranges */
	uint64_t mc_size;
	struct mc_bank {
		uint32_t  mcb_status;
#define	BANK_INSTALLED		0x80000000
#define	BANK_MIRROR_MODE	0x40000000	/* 0: normal  1: mirror */
#define	BANK_REWRITE_MODE	0x10000000

#define	BANK_PTRL_RUNNING	0x00000001

#define	MC_RETRY_COUNT	2
		mc_retry_info_t  mcb_retry_infos[MC_RETRY_COUNT];
		mc_retry_info_t	*mcb_retry_freelist;
		mc_retry_info_t	*mcb_retry_pending;
		mc_retry_info_t *mcb_active;
		int	  mcb_rewrite_count;

		uint64_t  mcb_reg_base;
		uint32_t  mcb_ptrl_cntl;
	} mc_bank[BANKNUM_PER_SB];
	uchar_t		mc_trans_table[2][64];	/* csX-mac-pa-trans-table */
	kmutex_t	mc_lock;
	scf_log_t	*mc_scf_log[BANKNUM_PER_SB];
	scf_log_t	*mc_scf_log_tail[BANKNUM_PER_SB];
	int		mc_scf_total[BANKNUM_PER_SB];
	struct memlist	*mlist;
	int		mc_scf_retry[BANKNUM_PER_SB];
	int		mc_last_error;
			/* number of times memory scanned */
	uint64_t	mc_period[BANKNUM_PER_SB];
	uint32_t	mc_speed;
	int		mc_speedup_period[BANKNUM_PER_SB];
	int		mc_tick_left;
	mc_dimm_info_t	*mc_dimm_list;
} mc_opl_t;

#define	IS_MIRROR(mcp, bn)	((mcp)->mc_bank[bn].mcb_status\
				& BANK_MIRROR_MODE)
typedef struct mc_addr {
	int ma_bd;		/* board number */
	int ma_phys_bd;	/* phyiscal board number */
	int ma_bank;		/* bank number */
	uint32_t ma_dimm_addr;	/* DIMM address (same format as ERR_ADD) */
} mc_addr_t;

typedef struct mc_rsaddr_info {		/* patrol restart address/info */
	struct mc_addr	mi_restartaddr;
	int		mi_valid;
	int		mi_injectrestart;
} mc_rsaddr_info_t;

typedef struct mc_flt_stat {
	uint32_t  mf_type;		/* fault type */
#define	FLT_TYPE_INTERMITTENT_CE	0x0001
#define	FLT_TYPE_PERMANENT_CE		0x0002
#define	FLT_TYPE_UE			0x0003
#define	FLT_TYPE_SUE			0x0004
#define	FLT_TYPE_MUE			0x0005
#define	FLT_TYPE_CMPE			0x0006
	uint32_t  mf_cntl;		/* MAC_BANKm_PTRL_CNTL Register */
	uint32_t  mf_err_add;	/* MAC_BANKm_{PTRL|MI}_ERR_ADD Register */
	uint32_t  mf_err_log;	/* MAC_BANKm_{PTRL|MI}_ERR_LOG Register */
	uint32_t  mf_synd;
	uchar_t   mf_errlog_valid;
	uchar_t   mf_dimm_slot;
	uchar_t   mf_dram_place;
	uint64_t  mf_flt_paddr;		/* faulty physical address */
	mc_addr_t mf_flt_maddr;		/* faulty DIMM address */
} mc_flt_stat_t;

typedef struct mc_aflt {
	uint64_t mflt_id;		/* gethrtime() at time of fault */
	mc_opl_t *mflt_mcp;		/* mc-opl structure */
	char *mflt_erpt_class;		/* ereport class name */
	int mflt_is_ptrl;		/* detected by PTRL or MI */
	int mflt_nflts;			/* 1 or 2 */
	int mflt_pr;			/* page retire flags */
	mc_flt_stat_t *mflt_stat[2];	/* fault status */
} mc_aflt_t;

typedef struct mc_flt_page {
	uint32_t err_add;		/* MAC_BANKm_{PTRL|MI}_ERR_ADD reg */
	uint32_t err_log;		/* MAC_BANKm_{PTRL|MI}_ERR_LOG reg */
	uint64_t fmri_addr;		/* FRU name string */
	uint32_t fmri_sz;		/* length of FRU name +1 */
} mc_flt_page_t;

#define	MAC_PTRL_STAT(mcp, i)		(mcp->mc_bank[i].mcb_reg_base)
#define	MAC_PTRL_CNTL(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x10)
#define	MAC_PTRL_ERR_ADD(mcp, i)	(mcp->mc_bank[i].mcb_reg_base + 0x20)
#define	MAC_PTRL_ERR_LOG(mcp, i)	(mcp->mc_bank[i].mcb_reg_base + 0x24)
#define	MAC_MI_ERR_ADD(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x28)
#define	MAC_MI_ERR_LOG(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x2c)
#define	MAC_STATIC_ERR_ADD(mcp, i)	(mcp->mc_bank[i].mcb_reg_base + 0x30)
#define	MAC_STATIC_ERR_LOG(mcp, i)	(mcp->mc_bank[i].mcb_reg_base + 0x34)
#define	MAC_RESTART_ADD(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x40)
#define	MAC_REWRITE_ADD(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x44)
#define	MAC_EG_ADD(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x48)
#define	MAC_EG_CNTL(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x4c)
#define	MAC_MIRR(mcp, i)		(mcp->mc_bank[i].mcb_reg_base + 0x50)

/* use PA[37:6] */
#define	MAC_RESTART_PA(pa)		((pa >> 6) & 0xffffffff)

/*
 * This is for changing MI_ERR_ADDR accuracy.
 * Last two bits of PTRL_ERR_ADDR are always 0.
 */
#define	ROUNDDOWN(a, n) (((a) & ~((n) - 1)))
#define	MC_BOUND_BYTE   4

/*
 * MAC_BANKm_PTRL_STAT_Register
 */
#define	MAC_STAT_PTRL_CE	0x00000020
#define	MAC_STAT_PTRL_UE	0x00000010
#define	MAC_STAT_PTRL_CMPE	0x00000008
#define	MAC_STAT_MI_CE		0x00000004
#define	MAC_STAT_MI_UE		0x00000002
#define	MAC_STAT_MI_CMPE	0x00000001

#define	MAC_STAT_PTRL_ERRS	(MAC_STAT_PTRL_CE|MAC_STAT_PTRL_UE\
				|MAC_STAT_PTRL_CMPE)
#define	MAC_STAT_MI_ERRS	(MAC_STAT_MI_CE|MAC_STAT_MI_UE\
				|MAC_STAT_MI_CMPE)

/*
 * MAC_BANKm_PTRL_CTRL_Register
 */
#define	MAC_CNTL_PTRL_START		0x80000000
#define	MAC_CNTL_USE_RESTART_ADD	0x40000000
#define	MAC_CNTL_PTRL_STOP		0x20000000
#define	MAC_CNTL_PTRL_INTERVAL		0x1c000000
#define	MAC_CNTL_PTRL_RESET		0x02000000
#define	MAC_CNTL_PTRL_STATUS		0x01000000
#define	MAC_CNTL_REW_REQ		0x00800000
#define	MAC_CNTL_REW_RESET		0x00400000
#define	MAC_CNTL_CS0_DEG_MODE		0x00200000
#define	MAC_CNTL_PTRL_CE		0x00008000
#define	MAC_CNTL_PTRL_UE		0x00004000
#define	MAC_CNTL_PTRL_CMPE		0x00002000
#define	MAC_CNTL_MI_CE			0x00001000
#define	MAC_CNTL_MI_UE			0x00000800
#define	MAC_CNTL_MI_CMPE		0x00000400
#define	MAC_CNTL_REW_CE			0x00000200
#define	MAC_CNTL_REW_UE			0x00000100
#define	MAC_CNTL_REW_END		0x00000080
#define	MAC_CNTL_PTRL_ADD_MAX		0x00000040
#define	MAC_CNTL_REW_CMPE		0x00000020

#define	MAC_CNTL_PTRL_ERR_SHIFT		13
#define	MAC_CNTL_MI_ERR_SHIFT		10

#define	MAC_CNTL_PTRL_PRESERVE_BITS	(MAC_CNTL_PTRL_INTERVAL)

#define	MAC_CNTL_PTRL_ERRS	(MAC_CNTL_PTRL_CE|MAC_CNTL_PTRL_UE\
				|MAC_CNTL_PTRL_CMPE)
#define	MAC_CNTL_MI_ERRS	(MAC_CNTL_MI_CE|MAC_CNTL_MI_UE\
				|MAC_CNTL_MI_CMPE)
#define	MAC_CNTL_REW_ERRS	(MAC_CNTL_REW_CE|MAC_CNTL_REW_CMPE|\
				MAC_CNTL_REW_UE|MAC_CNTL_REW_END)
#define	MAC_CNTL_ALL_ERRS	(MAC_CNTL_PTRL_ERRS|\
				MAC_CNTL_MI_ERRS|MAC_CNTL_REW_ERRS)

#define	MAC_ERRLOG_SYND_SHIFT		16
#define	MAC_ERRLOG_SYND_MASK		0xffff
#define	MAC_ERRLOG_DIMMSLOT_SHIFT	13
#define	MAC_ERRLOG_DIMMSLOT_MASK	0x7
#define	MAC_ERRLOG_DRAM_PLACE_SHIFT	8
#define	MAC_ERRLOG_DRAM_PLACE_MASK	0x1f

#define	MAC_SET_ERRLOG_INFO(flt_stat)				\
	(flt_stat)->mf_errlog_valid = 1;			\
	(flt_stat)->mf_synd = ((flt_stat)->mf_err_log >>	\
		MAC_ERRLOG_SYND_SHIFT) &			\
		MAC_ERRLOG_SYND_MASK;				\
	(flt_stat)->mf_dimm_slot = ((flt_stat)->mf_err_log >>	\
		MAC_ERRLOG_DIMMSLOT_SHIFT) &			\
		MAC_ERRLOG_DIMMSLOT_MASK;			\
	(flt_stat)->mf_dram_place = ((flt_stat)->mf_err_log >>	\
		MAC_ERRLOG_DRAM_PLACE_SHIFT) &			\
		MAC_ERRLOG_DRAM_PLACE_MASK;

extern void mc_write_cntl(mc_opl_t *, int, uint32_t);
#define	MAC_CMD(mcp, i, cmd)	mc_write_cntl(mcp, i, cmd)

#define	MAC_PTRL_START(mcp, i)	{ if (!(ldphysio(MAC_PTRL_CNTL(mcp, i))	\
				& MAC_CNTL_PTRL_START))			\
				MAC_CMD((mcp), (i), MAC_CNTL_PTRL_START); }

#define	MAC_PTRL_START_ADD(mcp, i)	MAC_CMD((mcp), (i),\
				MAC_CNTL_PTRL_START|MAC_CNTL_USE_RESTART_ADD)
#define	MAC_PTRL_STOP(mcp, i)	MAC_CMD((mcp), (i), MAC_CNTL_PTRL_STOP)
#define	MAC_PTRL_RESET(mcp, i)	MAC_CMD((mcp), (i), MAC_CNTL_PTRL_RESET)
#define	MAC_REW_REQ(mcp, i)	MAC_CMD((mcp), (i), MAC_CNTL_REW_REQ)
#define	MAC_REW_RESET(mcp, i)	MAC_CMD((mcp), (i), MAC_CNTL_REW_RESET)
#define	MAC_CLEAR_ERRS(mcp, i, errs)	MAC_CMD((mcp), (i), errs)
#define	MAC_CLEAR_ALL_ERRS(mcp, i)	MAC_CMD((mcp), (i),\
					MAC_CNTL_ALL_ERRS)
#define	MAC_CLEAR_MAX(mcp, i)	\
	MAC_CMD((mcp), (i), MAC_CNTL_PTRL_ADD_MAX)


/*
 * MAC_BANKm_PTRL/MI_ERR_ADD/LOG_Register
 */
#define	MAC_ERR_ADD_INVALID	0x80000000
#define	MAC_ERR_LOG_INVALID	0x00000080

/*
 * MAC_BANKm_STATIC_ERR_ADD_Register
 */
#define	MAC_STATIC_ERR_VLD	0x80000000

/*
 * MAC_BANKm_MIRR_Register
 */
#define	MAC_MIRR_MIRROR_MODE	0x80000000
#define	MAC_MIRR_BANK_EXCLUSIVE	0x40000000

#define	OPL_BOARD_MAX	16
#define	OPL_BANK_MAX	8

#define	MC_SET_REWRITE_MODE(mcp, bank)				\
	((mcp)->mc_bank[bank].mcb_status |= BANK_REWRITE_MODE)

#define	MC_CLEAR_REWRITE_MODE(mcp, bank)				\
	((mcp)->mc_bank[bank].mcb_status &= ~BANK_REWRITE_MODE)

#define	MC_REWRITE_MODE(mcp, bank)				\
	((mcp)->mc_bank[bank].mcb_status & BANK_REWRITE_MODE)

#define	MC_REWRITE_ACTIVE(mcp, bank)					\
	((mcp)->mc_bank[bank].mcb_active)

/*
 * MAC_BANKm_EG_ADD_Register
 */
#define	MAC_EG_ADD_MASK		0x7ffffffc
/*
 * To set the EG_CNTL register, bit[26-25] and
 * bit[21-20] must be cleared.  Then the other
 * control bit should be set.  Then the bit[26-25]
 * and bit[21-20] should be set while other bits
 * should be the same as before.
 */
#define	MAC_EG_CNTL_MASK	0x06300000

#define	MAC_EG_ADD_FIX		0x80000000
#define	MAC_EG_FORCE_DERR00	0x40000000
#define	MAC_EG_FORCE_DERR16	0x20000000
#define	MAC_EG_FORCE_DERR64	0x10000000
#define	MAC_EG_FORCE_DERR80	0x08000000
#define	MAC_EG_DERR_ALWAYS	0x02000000
#define	MAC_EG_DERR_ONCE	0x04000000
#define	MAC_EG_DERR_NOP		0x06000000
#define	MAC_EG_FORCE_READ00	0x00800000
#define	MAC_EG_FORCE_READ16	0x00400000
#define	MAC_EG_RDERR_ALWAYS	0x00100000
#define	MAC_EG_RDERR_ONCE	0x00200000
#define	MAC_EG_RDERR_NOP	0x00300000

#define	MAC_EG_SETUP_MASK	0xf9cfffff

/* For MAC-PA translation */
#define	MC_ADDRESS_BITS	40
#define	PA_BITS_FOR_MAC	39
#define	INDEX_OF_BANK_SUPPLEMENT_BIT	39
#define	MP_NONE		128
#define	MP_BANK_0	129
#define	MP_BANK_1	130
#define	MP_BANK_2	131

#define	CS_SHIFT	29
#define	MC_TT_ENTRIES	64
#define	MC_TT_CS	2


/* export interface for error injection */
extern int mc_inject_error(int error_type, uint64_t pa, uint32_t flags);

#define	MC_INJECT_NOP			0x0
#define	MC_INJECT_INTERMITTENT_CE	0x1
#define	MC_INJECT_PERMANENT_CE		0x2
#define	MC_INJECT_UE			0x3
#define	MC_INJECT_INTERMITTENT_MCE	0x11
#define	MC_INJECT_PERMANENT_MCE		0x12
#define	MC_INJECT_SUE			0x13
#define	MC_INJECT_MUE			0x14
#define	MC_INJECT_CMPE			0x15

#define	MC_INJECT_MIRROR_MODE		0x10
#define	MC_INJECT_MIRROR(x)		(x & MC_INJECT_MIRROR_MODE)

#define	MC_INJECT_FLAG_PREFETCH	0x1
#define	MC_INJECT_FLAG_NO_TRAP	MC_INJECT_FLAG_PREFETCH
#define	MC_INJECT_FLAG_RESTART	0x2
#define	MC_INJECT_FLAG_POLL	0x4
#define	MC_INJECT_FLAG_RESET	0x8
#define	MC_INJECT_FLAG_OTHER	0x10
#define	MC_INJECT_FLAG_LD	0x20
#define	MC_INJECT_FLAG_ST	0x40
#define	MC_INJECT_FLAG_PATH	0x80

#define	MCIOC			('M' << 8)
#define	MCIOC_FAULT_PAGE	(MCIOC|1)

#ifdef DEBUG

#define	MCI_NOP		0x0
#define	MCI_CE		0x1
#define	MCI_PERM_CE	0x2
#define	MCI_UE		0x3
#define	MCI_SHOW_ALL	0x4
#define	MCI_SHOW_NONE	0x5
#define	MCI_CMP		0x6
#define	MCI_ALLOC	0x7
#define	MCI_M_CE	0x8
#define	MCI_M_PCE	0x9
#define	MCI_M_UE	0xA
#define	MCI_SUSPEND	0xB
#define	MCI_RESUME	0xC

#endif

#ifdef	__cplusplus
}
#endif

#endif /* _SYS_MC_OPL_H */