view usr/src/uts/intel/io/amdzen/amdzen.h @ 20101:1a5588aae48c

13144 refactor amdf17nbdf into a nexus 13145 rewrite amdf17nbdf to use the ksensor framework 13146 Want a driver for AMD SMN user access Reviewed by: Patrick Mooney <pmooney@pfmooney.com> Reviewed by: Mike Zeller <mike.zeller@joyent.com> Reviewed by: Robert French <robert@robertdfrench.me> Approved by: Richard Lowe <richlowe@richlowe.net>
author Robert Mustacchi <rm@fingolfin.org>
date Wed, 08 Apr 2020 21:35:09 -0700
parents
children 4bb6be08390f
line wrap: on
line source

/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2020 Oxide Computer Company
 */

#ifndef _AMDZEN_H
#define	_AMDZEN_H

#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/list.h>
#include <sys/pci.h>
#include <sys/taskq.h>
#include <sys/bitmap.h>

/*
 * This header describes properties of the data fabric and our internal state
 * for the Zen Nexus driver.
 */

#ifdef __cplusplus
extern "C" {
#endif

/*
 * The data fabric devices are always defined to be on PCI bus zero starting at
 * device 0x18.
 */
#define	AMDZEN_DF_BUSNO		0x00
#define	AMDZEN_DF_FIRST_DEVICE	0x18

/*
 * The maximum amount of Data Fabric node's we can see. In Zen 1 there were up
 * to four per package.
 */
#define	AMDZEN_MAX_DFS		0x8

/*
 * The maximum number of PCI functions we expect to encounter on the data
 * fabric.
 */
#define	AMDZEN_MAX_DF_FUNCS	0x8


/*
 * Registers in the data fabric space that we care about for the purposes of the
 * nexus driver understanding itself.
 */

/*
 * This set of registers provides us access to the count of instances in the
 * data fabric and then a number of different pieces of information about them
 * like their type. Note, these registers require indirect access because the
 * information cannot be broadcast.
 */
#define	AMDZEN_DF_F0_FBICNT	0x40
#define	AMDZEN_DF_F0_FBICNT_COUNT(x)	BITX(x, 7, 0)
#define	AMDZEN_DF_F0_FBIINFO0	0x44
#define	AMDZEN_DF_F0_FBIINFO0_TYPE(x)		BITX(x, 3, 0)
typedef enum {
	AMDZEN_DF_TYPE_CCM = 0,
	AMDZEN_DF_TYPE_GCM,
	AMDZEN_DF_TYPE_NCM,
	AMDZEN_DF_TYPE_IOMS,
	AMDZEN_DF_TYPE_CS,
	AMDZEN_DF_TYPE_TCDX,
	AMDZEN_DF_TYPE_PIE,
	AMDZEN_DF_TYPE_SPF,
	AMDZEN_DF_TYPE_LLC,
	AMDZEN_DF_TYPE_CAKE
} amdzen_df_type_t;
#define	AMDZEN_DF_F0_FBIINFO0_SDP_WIDTH(x)	BITX(x, 5, 4)
typedef enum {
	AMDZEN_DF_SDP_W_64 = 0,
	AMDZEN_DF_SDP_W_128,
	AMDZEN_DF_SDP_W_256,
	AMDZEN_DF_SDP_W_512
} amdzen_df_sdp_width_t;
#define	AMDZEN_DF_F0_FBIINFO0_ENABLED(x)	BITX(x, 6, 6)
#define	AMDZEN_DF_F0_FBIINFO0_FTI_WIDTH(x)	BITX(x, 9, 8)
typedef enum {
	AMDZEN_DF_FTI_W_64 = 0,
	AMDZEN_DF_FTI_W_128,
	AMDZEN_DF_FTI_W_256,
	AMDZEN_DF_FTI_W_512
} amdzen_df_fti_width_t;
#define	AMDZEN_DF_F0_FBIINFO0_SDP_PCOUNT(x)	BITX(x, 13, 12)
#define	AMDZEN_DF_F0_FBIINFO0_FTI_PCOUNT(x)	BITX(x, 18, 16)
#define	AMDZEN_DF_F0_FBIINFO0_HAS_MCA(x)	BITX(x, 23, 23)
#define	AMDZEN_DF_F0_FBIINFO0_SUBTYPE(x)	BITX(x, 26, 24)
#define	AMDZEN_DF_SUBTYPE_NONE	0
typedef enum {
	AMDZEN_DF_CAKE_SUBTYPE_GMI = 1,
	AMDZEN_DF_CAKE_SUBTYPE_xGMI = 2
} amdzen_df_cake_subtype_t;

typedef enum {
	AMDZEN_DF_IOM_SUBTYPE_IOHUB = 1,
} amdzen_df_iom_subtype_t;

typedef enum {
	AMDZEN_DF_CS_SUBTYPE_UMC = 1,
	AMDZEN_DF_CS_SUBTYPE_CCIX = 2
} amdzen_df_cs_subtype_t;

#define	AMDZEN_DF_F0_FBIINFO1	0x48
#define	AMDZEN_DF_F0_FBIINFO1_FTI0_NINSTID(x)	BITX(x, 7, 0)
#define	AMDZEN_DF_F0_FBIINFO1_FTI1_NINSTID(x)	BITX(x, 15, 8)
#define	AMDZEN_DF_F0_FBIINFO1_FTI2_NINSTID(x)	BITX(x, 23, 16)
#define	AMDZEN_DF_F0_FBIINFO1_FTI3_NINSTID(x)	BITX(x, 31, 24)
#define	AMDZEN_DF_F0_FBIINFO2	0x4c
#define	AMDZEN_DF_F0_FBIINFO2_FTI4_NINSTID(x)	BITX(x, 7, 0)
#define	AMDZEN_DF_F0_FBIINFO2_FTI5_NINSTID(x)	BITX(x, 15, 8)
#define	AMDZEN_DF_F0_FBIINFO3	0x50
#define	AMDZEN_DF_F0_FBIINFO3_INSTID(x)		BITX(x, 7, 0)
#define	AMDZEN_DF_F0_FBIINFO3_FABID(x)		BITX(x, 13, 8)

/*
 * This register contains the information about the configuration of PCIe buses.
 * We care about finding which one has our BUS A, which is required to map it to
 * the northbridge.
 */
#define	AMDZEN_DF_F0_CFG_ADDR_CTL	0x84
#define	AMDZEN_DF_F0_CFG_ADDR_CTL_BUS_NUM(x)	BITX(x, 7, 0)

/*
 * Registers that describe how the system is actually put together.
 */
#define	AMDZEN_DF_F1_SYSCFG	0x200
#define	AMDZEN_DF_F1_SYSCFG_DIE_PRESENT(X)	BITX(x, 7, 0)
#define	AMDZEN_DF_F1_SYSCFG_DIE_TYPE(x)		BITX(x, 18, 11)
#define	AMDZEN_DF_F1_SYSCFG_MYDIE_TYPE(x)	BITX(x, 24, 23)
typedef enum {
	AMDZEN_DF_DIE_TYPE_CPU	= 0,
	AMDZEN_DF_DIE_TYPE_APU,
	AMDZEN_DF_DIE_TYPE_dGPU
} amdzen_df_die_type_t;
#define	AMDZEN_DF_F1_SYSCFG_OTHERDIE_TYPE(x)	BITX(x, 26, 25)
#define	AMDZEN_DF_F1_SYSCFG_OTHERSOCK(x)	BITX(x, 27, 27)
#define	AMDZEN_DF_F1_SYSCFG_NODEID(x)		BITX(x, 30, 28)

#define	AMDZEN_DF_F1_FIDMASK0	0x208
#define	AMDZEN_DF_F1_FIDMASK0_COMP_MASK(x)	BITX(x, 9, 0)
#define	AMDZEN_DF_F1_FIDMASK0_NODE_MASK(x)	BITX(x, 25, 16)
#define	AMDZEN_DF_F1_FIDMASK1	0x20C
#define	AMDZEN_DF_F1_FIDMASK1_NODE_SHIFT(x)	BITX(x, 3, 0)
#define	AMDZEN_DF_F1_FIDMASK1_SKT_SHIFT(x)	BITX(x, 9, 8)
#define	AMDZEN_DF_F1_FIDMASK1_DIE_MASK(x)	BITX(x, 18, 16)
#define	AMDZEN_DF_F1_FIDMASK1_SKT_MASK(x)	BITX(x, 26, 24)

/*
 * These two registers define information about the PSP and SMU on local and
 * remote dies (from the context of the DF instance). The bits are the same.
 */
#define	AMDZEN_DF_F1_PSPSMU_LOCAL	0x268
#define	AMDZEN_DF_F1_PSPSMU_REMOTE	0x268
#define	AMDZEN_DF_F1_PSPSMU_SMU_VALID(x)	BITX(x, 0, 0)
#define	AMDZEN_DF_F1_PSPSMU_SMU_UNITID(x)	BITX(x, 6, 1)
#define	AMDZEN_DF_F1_PSPSMU_SMU_COMPID(x)	BITX(x, 15, 8)
#define	AMDZEN_DF_F1_PSPSMU_PSP_VALID(x)	BITX(x, 16, 16)
#define	AMDZEN_DF_F1_PSPSMU_PSP_UNITID(x)	BITX(x, 22, 17)
#define	AMDZEN_DF_F1_PSPSMU_PSP_COMPID(x)	BITX(x, 31, 24)

#define	AMDZEN_DF_F1_CAKE_ENCR		0x2cc

/*
 * These registers are used to define Indirect Access, commonly known as FICAA
 * and FICAD for the system. While there are multiple copies of the indirect
 * access registers in device 4, we're only allowed access to one set of those
 * (which are the ones present here). Specifically the OS is given access to set
 * 3.
 */
#define	AMDZEN_DF_F4_FICAA	0x5c
#define	AMDZEN_DF_F4_FICAA_TARG_INST	(1 << 0)
#define	AMDZEN_DF_F4_FICAA_SET_REG(x)	((x) & 0x3fc)
#define	AMDZEN_DF_F4_FICAA_SET_FUNC(x)	(((x) & 0x7) << 11)
#define	AMDZEN_DF_F4_FICAA_SET_64B	(1 << 14)
#define	AMDZEN_DF_F4_FICAA_SET_INST(x)	(((x) & 0xff) << 16)
#define	AMDZEN_DF_F4_FICAD_LO	0x98
#define	AMDZEN_DF_F4_FICAD_HI	0x9c

/*
 * Northbridge registers that are relevant for the nexus, mostly for SMN.
 */
#define	AMDZEN_NB_SMN_ADDR	0x60
#define	AMDZEN_NB_SMN_DATA	0x64

/*
 * AMD PCI ID for reference
 */
#define	AMDZEN_PCI_VID_AMD	0x1022

typedef enum {
	AMDZEN_STUB_TYPE_DF,
	AMDZEN_STUB_TYPE_NB
} amdzen_stub_type_t;

typedef struct {
	list_node_t		azns_link;
	dev_info_t		*azns_dip;
	uint16_t		azns_vid;
	uint16_t		azns_did;
	uint16_t		azns_bus;
	uint16_t		azns_dev;
	uint16_t		azns_func;
	ddi_acc_handle_t	azns_cfgspace;
} amdzen_stub_t;

typedef enum  {
	AMDZEN_DFE_F_MCA	= 1 << 0,
	AMDZEN_DFE_F_ENABLED	= 1 << 1
} amdzen_df_ent_flags_t;

typedef struct {
	uint8_t adfe_drvid;
	amdzen_df_ent_flags_t adfe_flags;
	amdzen_df_type_t adfe_type;
	uint8_t adfe_subtype;
	uint8_t adfe_fabric_id;
	uint8_t adfe_inst_id;
	amdzen_df_sdp_width_t adfe_sdp_width;
	amdzen_df_fti_width_t adfe_fti_width;
	uint8_t adfe_sdp_count;
	uint8_t adfe_fti_count;
	uint32_t adfe_info0;
	uint32_t adfe_info1;
	uint32_t adfe_info2;
	uint32_t adfe_info3;
	uint32_t adfe_syscfg;
	uint32_t adfe_mask0;
	uint32_t adfe_mask1;
} amdzen_df_ent_t;

typedef enum {
	AMDZEN_DF_F_VALID		= 1 << 0,
	AMDZEN_DF_F_FOUND_NB		= 1 << 1
} amdzen_df_flags_t;

typedef struct {
	amdzen_df_flags_t	adf_flags;
	uint_t		adf_nb_busno;
	amdzen_stub_t	*adf_funcs[AMDZEN_MAX_DF_FUNCS];
	amdzen_stub_t	*adf_nb;
	uint_t		adf_nents;
	amdzen_df_ent_t	*adf_ents;
	uint32_t	adf_nodeid;
	uint32_t	adf_syscfg;
	uint32_t	adf_mask0;
	uint32_t	adf_mask1;
} amdzen_df_t;

typedef enum {
	AMDZEN_F_UNSUPPORTED		= 1 << 0,
	AMDZEN_F_DEVICE_ERROR		= 1 << 1,
	AMDZEN_F_MAP_ERROR		= 1 << 2,
	AMDZEN_F_SCAN_DISPATCHED	= 1 << 3,
	AMDZEN_F_SCAN_COMPLETE		= 1 << 4,
	AMDZEN_F_ATTACH_DISPATCHED	= 1 << 5,
	AMDZEN_F_ATTACH_COMPLETE	= 1 << 6
} amdzen_flags_t;

#define	AMDZEN_F_TASKQ_MASK	(AMDZEN_F_SCAN_DISPATCHED | \
    AMDZEN_F_SCAN_COMPLETE | AMDZEN_F_ATTACH_DISPATCHED | \
    AMDZEN_F_ATTACH_COMPLETE)

typedef struct amdzen {
	kmutex_t	azn_mutex;
	kcondvar_t	azn_cv;
	amdzen_flags_t	azn_flags;
	dev_info_t	*azn_dip;
	taskqid_t	azn_taskqid;
	uint_t		azn_nscanned;
	uint_t		azn_npresent;
	list_t		azn_df_stubs;
	list_t		azn_nb_stubs;
	uint_t		azn_ndfs;
	amdzen_df_t	azn_dfs[AMDZEN_MAX_DFS];
} amdzen_t;

typedef enum {
	AMDZEN_C_SMNTEMP = 1,
	AMDZEN_C_USMN
} amdzen_child_t;

/*
 * Functions for stubs.
 */
extern int amdzen_attach_stub(dev_info_t *, ddi_attach_cmd_t);
extern int amdzen_detach_stub(dev_info_t *, ddi_detach_cmd_t);

#ifdef __cplusplus
}
#endif

#endif /* _AMDZEN_H */