/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_AC_H
#define _SYS_AC_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
/* useful debugging stuff */
#define AC_ATTACH_DEBUG 0x1
#define AC_REGISTERS_DEBUG 0x2
/*
* OBP supplies us with two register sets for the AC nodes. They are:
*
* 0 miscellaneous regs
* 1 Cache tags
*
* We do not use the cache tags for anything in the kernel, so we
* do not map them in.
*/
/* Macros for physical acccess, fhc.h has to be present */
#define AC_OFFSET 0x00001000000ull
#define AC_CENTRAL 0x80000000
#define AC_ARB_FAST 0x00002000
#define AC_BCSR(board) (FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
AC_OFFSET + AC_OFF_BCSR)
/* Register set 0 Offsets */
#define AC_OFF_BRCS 0x10
#define AC_OFF_BCSR 0x20
#define AC_OFF_ESR 0x30
#define AC_OFF_EMR 0x40
#define AC_OFF_MEMCTL 0x60
#define AC_OFF_MEMDEC0 0x70
#define AC_OFF_MEMDEC1 0x80
#define AC_OFF_UPA0 0x2000
#define AC_OFF_UPA1 0x4000
#define AC_OFF_CNTR 0x6000
#define AC_OFF_MCCR 0x6020
/* Use predefined strings to name the kstats from this driver. */
#define AC_KSTAT_NAME "address_controller"
#define MEMCTL_KSTAT_NAMED "acmemctl"
#define MEMDECODE0_KSTAT_NAMED "acmemdecode0"
#define MEMDECODE1_KSTAT_NAMED "acmemdecode1"
#define CNTR_KSTAT_NAMED "accounter"
#define MCCR_KSTAT_NAMED "acmccr"
#define BANK_0_KSTAT_NAMED "acbank0"
#define BANK_1_KSTAT_NAMED "acbank1"
/* used for the picN kstats */
#define AC_NUM_PICS 2
#define AC_COUNTER_TO_PIC0(CNTR) ((CNTR) & 0xFFFFFFFFULL)
#define AC_COUNTER_TO_PIC1(CNTR) ((CNTR) >> 32)
/* used to clear/set the pcr */
#define AC_CLEAR_PCR(PCR) ((PCR) & ~(0x3F3F))
#define AC_SET_HOT_PLUG(PCR) ((PCR) | (0x3F3F))
/* used for programming the pic */
#define AC_SET_PIC_BUS_PAUSE(BRD) (0x80000000LL - 0x9ac4 - ((BRD) << 3))
/* defines for AC Board Configuration and Status Register */
#define NO_CACHE 0
#define CACHE_512K 2
#define CACHE_1M 3
#define CACHE_2M 4
#define CACHE_4M 5
#define CACHE_8M 6
#define CACHE_16M 7
#define ARB_MASTER 0x8000
#define ARB_INIT 0x4000
#define ARB_FAST 0x2000
#define FTC_CPAR 0x0200
#define AC_CSR_REFEN (1ULL << 27)
/* defines for Memory decode registers */
#define AC_MEM_VALID 0x8000000000000000ULL
/* size of a memory SIMM group */
#define RASIZE0(memctl) (8 << ((((memctl) >> 8) & 0x7) << 1))
#define RASIZE1(memctl) (8 << ((((memctl) >> 11) & 0x7) << 1))
#define RATBL0(memctl) (((memctl) >> 8) & 0x7)
#define RATBL1(memctl) (((memctl) >> 11) & 0x7)
/*
* Interleave factor of a memory SIMM group.
* Possible values are 1, 2, 4, 8, and 16. 1 means not interleaved.
* Larger groups can be interleaved with smaller groups. Groups
* on the same board can be interleaved as well.
*/
#define INTLV0(memctl) (1 << ((memctl) & 0x7))
#define INTLV1(memctl) (1 << (((memctl) >> 3) & 0x7))
#define INTVAL0(memctl) ((memctl) & 0x7)
#define INTVAL1(memctl) (((memctl) >> 3) & 0x7)
/*
* Physical base mask of a memory SIMM group. Note that this is
* not the real physical base, and is just used to match up the
* interleaving of groups. The mask bits (UK) are used to mask
* out the match (UM) field so that the bases can be compared.
*/
#define GRP_UK(memdec) (((memdec) >> 39) & 0xFFF)
#define GRP_UM(memdec) (((memdec) >> 12) & 0x7FFF)
#define GRP_BASE(memdec) (GRP_UM(memdec) & ~(GRP_UK(memdec)))
#define GRP_LK(memdec) (((memdec) >> 6) & 0xf)
#define GRP_LM(memdec) ((memdec) & 0xf)
#define GRP_LBASE(memdec) (GRP_LM(memdec) & ~(GRP_LK(memdec)))
#define GRP_REALBASE(m) ((GRP_BASE(m) << 26) | (GRP_LBASE(m) << 6))
#define GRP_UK2SPAN(memdec) ((GRP_UK(memdec) + 1) << 26)
#define GRP_SPANMB(memdec) (GRP_UK2SPAN(memdec) >> 20)
/*
* memory states and conditions for sunfire memory system
*/
enum ac_bank_id { Bank0 = 0, Bank1 = 1 };
enum ac_bank_status { StUnknown = 0, StNoMem, StBad, StActive, StSpare };
enum ac_bank_condition { ConUnknown = 0, ConOK, ConFailing, ConFailed,
ConTest, ConBad };
/*
* AC memory bank ioctl interface.
*/
/* 'G' (for gigabytes!) does not appear to be used elsewhere in the kernel */
#define AC_IOC ('G'<<8)
/*
* For all AC_MEM_ ioctls the arg pointer points to a sysc_cfga_cmd_t
* except for AC_MEM_ADMIN_VER. The private pointer then points to a
* structure of the appropriate type, if required.
*/
#define AC_MEM_ADMIN_VER (AC_IOC|0) /* arg is &ac_mem_version_t */
#define AC_MEM_CONFIGURE (AC_IOC|1) /* private == NULL */
#define AC_MEM_UNCONFIGURE (AC_IOC|2) /* private == NULL */
#define AC_MEM_STAT (AC_IOC|3) /* ac_stat_t */
#define AC_MEM_TEST_START (AC_IOC|4) /* ac_mem_test_start_t */
#define AC_MEM_TEST_STOP (AC_IOC|5) /* ac_mem_test_stop_t */
#define AC_MEM_TEST_READ (AC_IOC|6) /* ac_mem_test_read_t */
#define AC_MEM_TEST_WRITE (AC_IOC|7) /* ac_mem_test_write_t */
#define AC_MEM_EXERCISE (AC_IOC|128) /* various */
#define AC_OUTPUT_LEN MAXPATHLEN /* output str len */
typedef enum {
AC_ERR_DEFAULT = 0, /* generic errors */
AC_ERR_INTRANS, /* hardware in transition */
AC_ERR_UTHREAD, /* can't stop user thread */
AC_ERR_KTHREAD, /* can't stop kernel thread */
AC_ERR_SUSPEND, /* can't suspend a device */
AC_ERR_RESUME, /* can't resume a device */
AC_ERR_POWER, /* not enough power for slot */
AC_ERR_COOLING, /* not enough cooling for slot */
AC_ERR_PRECHARGE, /* not enough precharge for slot */
AC_ERR_HOTPLUG, /* Hot Plug Unavailable */
AC_ERR_HW_COMPAT, /* incompatible hardware found during dr */
AC_ERR_NON_DR_PROM, /* prom not support Dynamic Reconfiguration */
AC_ERR_CORE_RESOURCE, /* core resource cannot be removed */
AC_ERR_PROM, /* error encountered in OBP/POST */
AC_ERR_DR_INIT, /* error encountered in sysc_dr_init op */
AC_ERR_NDI_ATTACH, /* error encountered in NDI attach operations */
AC_ERR_NDI_DETACH, /* error encountered in NDI detach operations */
AC_ERR_RSTATE, /* wrong receptacle state */
AC_ERR_OSTATE, /* wrong occupant state */
AC_ERR_COND, /* invalid condition */
AC_ERR_BD, /* invalid board id */
AC_ERR_BD_TYPE, /* invalid board type */
AC_ERR_BD_STATE, /* invalid board state */
AC_ERR_MEM_PERM, /* no write permission */
AC_ERR_MEM_BK, /* invalid memory bank */
AC_ERR_MEM_TEST, /* invalid memory test id */
AC_ERR_MEM_TEST_PAR, /* invalid memory test parameter(s) */
AC_ERR_KPM_CANCELLED, /* kphysm_del_cancel (for complete) */
AC_ERR_KPM_REFUSED, /* kphysm_pre_del failed (for complete) */
AC_ERR_KPM_SPAN, /* memory already in use (add) */
AC_ERR_KPM_DUP, /* memory span duplicate (delete) */
AC_ERR_KPM_FAULT, /* memory access test failed (add) */
AC_ERR_KPM_RESOURCE, /* some resource was not available */
AC_ERR_KPM_NOTSUP, /* operation not supported */
AC_ERR_KPM_NOHANDLES, /* cannot allocate any more handles */
AC_ERR_KPM_NONRELOC, /* non-relocatable pages in span */
AC_ERR_KPM_HANDLE, /* bad handle supplied */
AC_ERR_KPM_BUSY, /* memory in span is being deleted */
AC_ERR_KPM_NOTVIABLE, /* vM viability test failed */
AC_ERR_KPM_SEQUENCE, /* function called out of sequence */
AC_ERR_KPM_NOWORK, /* no pages to delete */
AC_ERR_KPM_NOTFINISHED, /* thread not finished */
AC_ERR_KPM_NOTRUNNING, /* thread not running */
AC_ERR_VMEM, /* insufficient virtual memory */
AC_ERR_INTR, /* delete interrupt by user */
AC_ERR_TIMEOUT, /* delete timed out */
AC_ERR_MEM_DEINTLV /* could not de-interleave memory */
} ac_err_t;
/*
* Config admin command structure for AC_MEM ioctls.
*/
typedef struct ac_cfga_cmd {
uint_t force:1; /* force this state transition */
uint_t test:1; /* Need to test hardware */
int arg; /* generic data for test */
ac_err_t errtype; /* error code returned */
char *outputstr; /* output returned from ioctl */
void *private; /* command private data */
} ac_cfga_cmd_t;
typedef struct ac_cfga_cmd32 {
uint_t force:1; /* force this state transition */
uint_t test:1; /* Need to test hardware */
int arg; /* generic data for test */
ac_err_t errtype; /* error code returned */
caddr32_t outputstr; /* output returned from ioctl */
caddr32_t private; /* command private data */
} ac_cfga_cmd32_t;
typedef uint_t ac_mem_version_t; /* platform interface rev */
#define AC_MEM_ADMIN_VERSION 1
typedef uint_t mem_test_handle_t;
typedef struct {
uint64_t module_id;
uint64_t afsr;
uint64_t afar;
uint64_t udbh_error_reg;
uint64_t udbl_error_reg;
} sunfire_processor_error_regs_t;
/*
* page_size gives the requires size for the read or write buffer.
* A read can be restricted to one or more line_size units starting
* at a multiple of line_size units from the start of the page.
* afar_base is the physical base of the bank being tested so
* that the afar value can be translated to an offset into the bank.
*/
typedef struct {
mem_test_handle_t handle;
pid_t tester_pid; /* PID of test starter */
sysc_cfga_cond_t prev_condition;
u_longlong_t bank_size; /* bytes */
uint_t page_size; /* bytes */
uint_t line_size; /* bytes */
u_longlong_t afar_base;
} ac_mem_test_start_t;
typedef struct {
mem_test_handle_t handle;
sysc_cfga_cond_t condition;
} ac_mem_test_stop_t;
/*
* line_offset is in the range 0 - (page_size/line_size)-1
* line_count is in the range 1 - (page_size/line_size)
*/
typedef struct {
u_longlong_t page_num;
uint_t line_offset;
uint_t line_count;
} ac_test_addr_t;
/*
* Data will be transferred in/out of the buffer at:
* (page_buf + (line_offset*line_size))
*/
typedef struct {
mem_test_handle_t handle;
void *page_buf;
ac_test_addr_t address;
sunfire_processor_error_regs_t *error_buf;
} ac_mem_test_read_t;
typedef struct {
mem_test_handle_t handle;
void *page_buf;
ac_test_addr_t address;
} ac_mem_test_write_t;
#ifdef _SYSCALL32
/* Kernel's view of ILP32 structure version. */
typedef struct {
mem_test_handle_t handle;
caddr32_t page_buf; /* void * */
ac_test_addr_t address;
caddr32_t error_buf; /* sunfire_processor_error_regs_t */
} ac_mem_test_read32_t;
typedef struct {
mem_test_handle_t handle;
caddr32_t page_buf; /* void * */
ac_test_addr_t address;
} ac_mem_test_write32_t;
#endif /* _SYSCALL32 */
/* structure returned from AC_MEM_STAT ioctl */
typedef struct {
sysc_cfga_rstate_t rstate;
sysc_cfga_ostate_t ostate;
sysc_cfga_cond_t condition;
time_t status_time;
uint_t board;
uint_t real_size;
uint_t use_size;
uint_t busy; /* add/delete in progress */
uint_t page_size; /* bytes */
uint64_t phys_pages;
uint64_t managed;
uint64_t nonrelocatable;
/* to supply address, group, info */
uint64_t ac_memctl;
uint64_t ac_decode0;
uint64_t ac_decode1;
} ac_stat_t;
#ifdef _SYSCALL32
/* Kernel's view of ILP32 structure version. */
typedef struct {
sysc_cfga_rstate_t rstate;
sysc_cfga_ostate_t ostate;
sysc_cfga_cond_t condition;
time32_t status_time;
uint_t board;
uint_t real_size;
uint_t use_size;
uint_t busy; /* add/delete in progress */
uint_t page_size; /* bytes */
uint64_t phys_pages;
uint64_t managed;
uint64_t nonrelocatable;
/* to supply address, group, info */
uint64_t ac_memctl;
uint64_t ac_decode0;
uint64_t ac_decode1;
} ac_stat32_t;
#endif /* _SYSCALL32 */
/* Command values in cmd_cfga.arg for the AC_MEM_EXERCISE ioctl. */
#define AC_MEMX_RELOCATE_ALL 0
/* Stats structure for AC_MEMX_RELOCATE_ALL (cmd_cfga.private != NULL). */
struct ac_memx_relocate_stats {
uint_t base;
uint_t npgs;
uint_t nopaget;
uint_t nolock;
uint_t isfree;
uint_t reloc;
uint_t noreloc;
};
/* End of ioctl interface. */
#if defined(_KERNEL)
typedef struct {
ac_cfga_cmd_t cmd_cfga;
char *errbuf; /* internal error buffer */
struct ac_soft_state *softsp;
uint_t bank; /* Decoded bank number. */
} ac_cfga_pkt_t;
#define AC_ERR_SET(pkt, err) (pkt)->cmd_cfga.errtype = (err)
#define MEM_BOARD_VISIBLE(BD) \
((BD)->sc.rstate == SYSC_CFGA_RSTATE_CONNECTED && \
(BD)->sc.ostate == SYSC_CFGA_OSTATE_CONFIGURED)
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#define AC_BANK0_STATUS "bank-0-status"
#define AC_BANK1_STATUS "bank-1-status"
#define AC_BANK_NOMEM "nomem"
#define AC_BANK_OK "ok"
#define AC_BANK_SPARE "spare"
#define AC_BANK_FAILED "failed"
/*
* Test for a valid size setting. The size must be set as
* a contiguous number of bits starting at the least significant bit.
* Adding one to such a number causes a carry to be propagated to
* the first zero bit, eg 00111 -> 01000. Thus for a correctly
* formed value, the AND of the two numbers is 0.
*/
#define GRP_SIZE_IS_SET(memdec) ((GRP_UK(memdec) & (GRP_UK(memdec) + 1)) == 0)
/* set the decode register bits according to the desired bank layout */
#define SETUP_DECODE(addr, mb, intlv, group) \
((((addr) >> 26) & 0x7fffULL) << 12) | /* UM */ \
((((mb) >> 6) - 1ULL) << 39) | /* UK */ \
((group) & 0xfULL) | /* LM */ \
((0xfULL << (intlv) & 0xfULL) << 6) /* LK */
/*
* Driver minor number macros.
*/
#define AC_GETINSTANCE(M) ((M) >> 1)
#define AC_GETBANK(M) ((M) & 1)
#define AC_PUTINSTANCE(I) ((I) << 1)
/*
* Attachment point names.
*/
#define NAME_BANK0 "bank0"
#define NAME_BANK1 "bank1"
/*
* Memory Database
* This information is generally accessed through the bd_list so we will
* just protect it by that for now.
*/
struct ac_mem_info {
int busy; /* A bank is in transition */
time_t status_change; /* Time of last change */
sysc_cfga_rstate_t rstate;
sysc_cfga_ostate_t ostate;
sysc_cfga_cond_t condition;
uint_t real_size; /* Real size in MB of bank */
uint_t use_size; /* In use size in MB */
};
/* Structures used in the driver to manage the hardware */
struct ac_soft_state {
dev_info_t *dip; /* dev info of myself */
dev_info_t *pdip; /* dev info of my parent */
int board; /* Board number for this AC */
/* fields protected by bd_list lock */
struct ac_mem_info bank[2]; /* memory bank information */
/* Mapped addresses of registers */
void *ac_base; /* Base address of Address Controller */
volatile uint32_t *ac_id; /* ID register */
volatile uint64_t *ac_memctl; /* Memory Control */
volatile uint64_t *ac_memdecode0; /* Memory Decode 0 */
volatile uint64_t *ac_memdecode1; /* Memory Decode 1 */
volatile uint64_t *ac_counter; /* AC counter register */
volatile uint32_t *ac_mccr; /* AC Counter control */
kstat_t *ac_ksp;
kstat_t *ac_counters_ksp; /* performance counter kstat */
};
extern void ac_blkcopy(caddr_t, caddr_t, uint_t, uint_t);
extern void ac_mapin(uint64_t, caddr_t);
extern void ac_unmap(caddr_t);
/* kstat structure used by ac to pass data to user programs. */
struct ac_kstat {
struct kstat_named ac_memctl; /* AC Memory control */
struct kstat_named ac_memdecode0; /* AC Memory Decode Bank 0 */
struct kstat_named ac_memdecode1; /* AC Memory Decode Bank 1 */
struct kstat_named ac_mccr; /* AC Mem Counter Control */
struct kstat_named ac_counter; /* AC Counter */
struct kstat_named ac_bank0_status;
struct kstat_named ac_bank1_status;
};
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _SYS_AC_H */