/*
 * Copyright (c) 1991-1998, by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef _SYS_PCI_VAR_H
#define	_SYS_PCI_VAR_H

#pragma ident	"@(#)pci_var.h	1.41	98/03/02 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef _XFIRE
/*
 * Interrupt target translation data
 * (for Starfire support)
 */
struct psycho_ittrans_data {
	kmutex_t ittrans_lock;			/* lock to protect ITTR array */
	volatile uint64_t *ittrans_mondovec[32]; /* mondovecreg addrs array */
	uint64_t ittransreg_physaddr[32];	/* ITTREG physaddrs array */
};

#define	free_psycho_ittrans(p)						\
	if ((p)->psycho_ittrans) {					\
		mutex_destroy(&(p)->psycho_ittrans->ittrans_lock);	\
		kmem_free((p)->psycho_ittrans,				\
		    sizeof (struct psycho_ittrans_data));		\
		(p)->psycho_ittrans = 0;				\
	}

#endif _XFIRE

typedef struct pci_devstate pci_devstate_t;
typedef struct psycho_devstate psycho_devstate_t;
typedef struct psycho_ino_info psycho_ino_info_t;
typedef struct psycho_intr_req psycho_intr_req_t;

typedef enum { NEW = 0, ATTACHED, RESUMED, DETACHED,
		SUSPENDED, PM_SUSPENDED } driver_state_t;

typedef enum { INO_FREE = 0, INO_SINGLE, INO_SHARED } ino_state_t;

typedef enum { PBM_SPEED_33MHZ, PBM_SPEED_66MHZ } pbm_speed_t;

typedef enum { MR_SHARED, MR_EXCLUSIVE } map_reg_t;

/*
 * The following typedef is used to represent a
 * 1275 "bus-range" property of a PCI Bus node.
 */
typedef struct {
	u_int lo;
	u_int hi;
} pci_bus_range_t;

/*
 * Data structure to support PCI -> UPA range properties.
 */
struct pci_upa_rangespec {
	uint32_t pci_phys_hi;		/* child's range, hi word */
	uint32_t pci_phys_mid;		/* child's range, middle word */
	uint32_t pci_phys_low;		/* child's range, low word */
	uint32_t upa_phys_hi;		/* Parents range hi word */
	uint32_t upa_phys_low;		/* Parents range low word */
	uint32_t rng_size_hi;		/* high word of size field */
	uint32_t rng_size_low;		/* low word of size field */
};

/* Fault handler dispatch structure */
struct fault_hdlr {
	struct fault_hdlr_info info;
	struct fault_hdlr_data data;
	struct fault_hdlr *next;
};

/*
 * The following structure represents an entry in an INO's
 * device list.
 */
struct psycho_intr_req {
	dev_info_t *dip;		/* devinfo structure */
	u_int (*handler)();		/* interrupt handler */
	caddr_t handler_arg;		/* interrupt handler argument */
	ddi_acc_handle_t config_handle;	/* config space reg map handle */
	psycho_intr_req_t *next;	/* next entry in list */
};

/*
 * per ino structure
 *
 * Each psycho ino has one of the following structures associate
 * with it.
 */
struct psycho_ino_info {
/*
	struct pciintrspec intrspec;
*/
	u_longlong_t *clear_reg;	/* ino's clear interrupt register */
	u_longlong_t *map_reg;		/* ino's interrupt map register */
	map_reg_t map_reg_type;		/* map reg count (if shared) */
	u_int *map_reg_counter;		/* map reg shared or exclusive */
	ino_state_t state;		/* state of ino handler list */
	psycho_intr_req_t *head;	/* interrupt handler list head */
	psycho_intr_req_t *tail;	/* interrupt handler list tail */
	psycho_intr_req_t *start;	/* staring point in handler list */
	u_int size;			/* size of list */
	kmutex_t mutex1;		/* for locking adds/deletes */
	kmutex_t mutex2;		/* for locking adds/deletes/intrs */
	u_int iblock_cookie;
	u_int idevice_cookie;
	u_int ino;
	psycho_devstate_t *psycho_p;
};

/*
 * per-psycho soft state structure:
 */
struct psycho_devstate {

	dev_info_t *dip;		/* devinfo structure */
	u_int upa_id;			/* upa id */
	driver_state_t state;
	u_char impl_num;		/* chip implementation number */
	u_char ver_num;			/* chip version number */

	/*
	 * pointers back to the PBM A & B soft state structures:
	 */
	pci_devstate_t *pci_a_p;
	pci_devstate_t *pci_b_p;

	/*
	 * virtual addresses of common registers:
	 */
	u_longlong_t *reg_base;
	volatile u_longlong_t *ctrl_reg;
	volatile u_longlong_t *iommu_ctrl_reg;
	volatile u_longlong_t *tsb_base_addr_reg;
	volatile u_longlong_t *iommu_flush_reg;
	volatile u_longlong_t *imap_reg;
	volatile u_longlong_t *obio_imap_reg;
	volatile u_longlong_t *cleari_reg;
	volatile u_longlong_t *obio_cleari_reg;
	volatile u_longlong_t *intr_retry_timer_reg;
	volatile u_longlong_t *ecc_ctrl_reg;
	volatile u_longlong_t *ue_afsr;
	volatile u_longlong_t *ue_afar;
	volatile u_longlong_t *ce_afsr;
	volatile u_longlong_t *ce_afar;
	volatile u_longlong_t *tlb_tag_diag_acc;
	volatile u_longlong_t *tlb_data_diag_acc;
	volatile u_longlong_t *pci_int_state_diag_reg;
	volatile u_longlong_t *obio_int_state_diag_reg;
	volatile u_longlong_t *perf_mon_cntrl_reg;
	volatile u_longlong_t *perf_counter_reg;
	volatile u_longlong_t *obio_graph_imap_reg;
	volatile u_longlong_t *obio_exp_imap_reg;

	/*
	 * Interrupts structures for correctable errors,
	 * uncorrectable errors and power management
	 * interrupts.
	 */
	u_int ue_mondo;
	u_int ce_mondo;
	u_int thermal_mondo;
	u_int power_fail_mondo;
	u_int power_button_mondo;

	/*
	 * iommu data:
	 */
	u_longlong_t *tsb_vaddr;	/* virtual address iommu tsb */
	char dvma_map_name[32];		/* string storage. */
	struct map *dvma_map;		/* resource map for DVMA space */
	uintptr_t dvma_call_list_id;	/* DVMA space call back list id */
	u_int iommu_tsb_entries;	/* max entries for tsb */
	u_long iommu_dvma_base;		/* dvma base address */
	u_long iommu_dvma_end;		/* largest dvma address */
	u_long dvma_reserve;		/* for fast dvma interfaces */
#ifndef	_SBSD_DR
	u_int spare_slot;		/* using spare tsb allocation */
#endif	/* ! _SBSD_DR */

	/*
	 * ino structures:
	 */
#define	PSYCHO_MAX_INO		0x3f
	psycho_ino_info_t ino_info[PSYCHO_MAX_INO + 1];
#define	PSYCHO_INTR_MAP_REGS	0x8
	u_int ino_map_reg_counter[PSYCHO_INTR_MAP_REGS];
	u_longlong_t imap_reg_state[PSYCHO_MAX_INO + 1];
	u_longlong_t obio_graph_imap_reg_state;
	u_longlong_t obio_exp_imap_reg_state;
	kmutex_t ino_mutex;

#ifdef _XFIRE
	int	intr_mapping_ign;	/* placeholder for the IGN */
	struct psycho_ittrans_data *psycho_ittrans; /* intr tgt translation */
#endif _XFIRE
};

/*
 * per-pci (PBM) soft state structure:
 */
struct pci_devstate {

	psycho_devstate_t *psycho_p;	/* pointer per-psycho soft state */
	dev_info_t *dip;		/* devinfo structure */
	u_int upa_id;			/* upa id */
	pbm_speed_t pbm_speed;		/* PBM running at 33 or 66 MHz */
	driver_state_t state;

	/*
	 * generic pci bus node information:
	 */
	pci_bus_range_t bus_range;	/* bus range property */

	/*
	 * device node address property:
	 */
	caddr_t address[3];

	/*
	 * access handles in case we need to map the registers ourself:
	 */
	ddi_acc_handle_t ac[3];

	/*
	 * virtual addresses of PBM registers:
	 */
	u_longlong_t *reg_base;
	volatile u_longlong_t *ctrl_reg;
	volatile u_longlong_t *sbuf_ctrl_reg;
	volatile u_longlong_t *sbuf_invl_reg;
	volatile u_longlong_t *sbuf_sync_reg;
	volatile u_longlong_t *afsr;
	volatile u_longlong_t *afar;
	volatile u_longlong_t *diag;
	volatile caddr_t config_space_base;
	volatile u_short *config_command_reg;
	volatile u_short *config_status_reg;
	volatile u_char *config_latency_reg;
	volatile u_longlong_t *sbuf_page_tag_diag_acc;
	volatile u_longlong_t *sbuf_line_tag_diag_acc;

	/*
	 * address spaces:
	 */
	uint64_t base;			/* lowest chip address */
	uint64_t end;			/* highest chip address */
	uint64_t mem_base;		/* base of pci bus memory space */
	uint64_t mem_end;
	uint64_t io_base;		/* base of pci bus i/o space */
	uint64_t io_end;
	uint64_t config_base;		/* base of pci bus config space */
	uint64_t config_end;

	/*
	 * Interrupt cookie for async bus error
	 * interrupts.
	 */
#if defined(USE_DDI_ADD_INTR)
	ddi_iblock_cookie_t be_iblock_cookie;
#endif
	u_int be_mondo;
	kmutex_t flt_lst_mutex;		/* Fault handler list mutex */
	struct fault_hdlr *flt_lst;	/* Fault handling list */

	/*
	 * dma handle data:
	 */
	caddr_t handle_pool_base;	/* base for kmem_fast_alloc */
	kmutex_t handle_pool_mutex;	/* mutex for allocator */
	uintptr_t handle_call_list_id;	/* call back list id */

	/*
	 * streaming cache information:
	 */
	kmutex_t sync_mutex;		/* mutex for flush/sync register */
	caddr_t sync_flag_base;		/* base va of sync flag block */
	u_longlong_t *sync_flag_vaddr;	/* va of sync flag */
	u_longlong_t sync_flag_addr;	/* pa of sync flag */

	/*
	 * cpr support:
	 */
#define	PCI_MAX_DEVICES		32
#define	PCI_MAX_FUNCTIONS	8
#define	PCI_MAX_CHILDREN	PCI_MAX_DEVICES * PCI_MAX_FUNCTIONS
	u_int config_state_index;
	struct {
		dev_info_t *dip;
		u_short command;
		u_char cache_line_size;
		u_char latency_timer;
		u_char header_type;
		u_char sec_latency_timer;
		u_char bridge_control;
	} config_state[PCI_MAX_CHILDREN];

	/*
	 * Register mapping structs using ranges property:
	 */
	struct pci_upa_rangespec *rangep;
	int range_cnt;

	/* Interrupt support */
	int intr_map_size;
	struct intr_map *intr_map;
	struct intr_map_mask *intr_map_mask;
#ifdef _XFIRE
	int	intr_map_mask_size;
#endif _XFIRE
};

#define	PCI_SBUF_ENTRIES	16	/* number of i/o cache lines */
#define	PCI_SBUF_LINE_SIZE	64	/* size of i/o cache line */
#define	PCI_SYNC_FLAG_SIZE	64	/* size of i/o cache sync buffer */

#define	PCI_CACHE_LINE_SIZE	(PCI_SBUF_LINE_SIZE / 4)

/*
 * Contains a list of cookies created by create_bypass_cookies.
 */
typedef struct pci_dma_cookielist {
	u_int ncookies;
	ddi_dma_cookie_t cookies[1];
} pci_dma_cookielist_t;

#define	COOKIELIST_SIZE(ncookies)				\
	(sizeof (pci_dma_cookielist_t) +			\
		(ncookies - 1) * sizeof (ddi_dma_cookie_t))

/*
 * This structure contains nexus private data that is held in the dma
 * handle.  The contract is that pci_dma_allochdl and pci_dma_map
 * will allocate this structure and set both pointers in it to NULL.
 * pci_dma_freehdl and the DDI_DMA_FREE request of pci_dma_mctl
 * will free this structure and any structures below it if they
 * exist.  Note that the fast dvma routines cannot be mixed with
 * the traditional dvma routines - the fast dvma routines have
 * their own use for the dmai_nexus_private pointer.
 */
typedef struct pci_dmai_nexus_private {
	u_int *pfn_listp;			/* page frame number list */
	pci_dma_cookielist_t *cookie_listp;	/* bypass cookies */
} pci_dmai_nexus_private_t;

/*
 * PSYCHO INO macros:
 */
#define	OBIO_INO(ino)			((ino) & 0x20)
#define	MONDO_TO_INO(mondo)		((mondo) & 0x3f)
#define	MONDO_TO_UPA_ID(mondo)		(((mondo) >> 6) & 0x3f)
#define	MAKE_MONDO(upa_id, ino)		(((upa_id) << 6) | (ino))
#define	INO_ON_BUSA(ino)		(!((ino) & 0xfffffff8))
#define	INO_ON_BUSB(ino)		((ino) & 0x30)
#define	INO_TO_SLOT(ino)		(((ino) >> 2) & 0x3)
#define	INO_START_BIT(ino)		(((ino) & 0x1f) << 1)

/*
 * PSYCHO and PBM soft state macros:
 */
#define	get_pci_soft_state(i)	\
	((pci_devstate_t *)ddi_get_soft_state(per_pci_state, (i)))

#define	alloc_pci_soft_state(i)	\
	ddi_soft_state_zalloc(per_pci_state, (i))

#define	free_pci_soft_state(i)	\
	ddi_soft_state_free(per_pci_state, (i))

#define	get_psycho_soft_state(i)	\
	((psycho_devstate_t *)ddi_get_soft_state(per_psycho_state, (i)))

#define	alloc_psycho_soft_state(i)	\
	ddi_soft_state_zalloc(per_psycho_state, (i))

#define	free_psycho_soft_state(i)	\
	ddi_soft_state_free(per_psycho_state, (i))

/*
 * misc macros for dma handles and cookies:
 */
#define	MAKE_DMA_COOKIE(cp, address, size)	\
	{					\
		(cp)->dmac_notused = 0;		\
		(cp)->dmac_type = 0;		\
		(cp)->dmac_address = (address);	\
		(cp)->dmac_size = (size);	\
	}

#define	HAS_REDZONE(mp)	(((mp)->dmai_rflags & DDI_DMA_REDZONE) ? 1 : 0)

/*
 * flags for overloading dmai_inuse field of the dma request
 * structure:
 */
#define	dmai_flags		dmai_inuse
#define	DMAI_FLAGS_INUSE	0x1
#define	DMAI_FLAGS_BYPASS	0x2
#define	DMAI_FLAGS_PEER_TO_PEER	0x4

#define	PCI_PULSE_INO	0x80000000

/*
 * debugging definitions:
 */
#if defined(DEBUG)
#define	D_IDENTIFY	0x00000001
#define	D_ATTACH	0x00000002
#define	D_DETACH	0x00000004
#define	D_MAP		0x00000008
#define	D_CTLOPS	0x00000010
#define	D_G_ISPEC	0x00000020
#define	D_A_ISPEC	0x00000040
#define	D_R_ISPEC	0x00000080
#define	D_DMA_MAP	0x00000100
#define	D_DMA_CTL	0x00000200
#define	D_DMA_ALLOCH	0x00000400
#define	D_DMA_FREEH	0x00000800
#define	D_DMA_BINDH	0x00001000
#define	D_DMA_UNBINDH	0x00002000
#define	D_DMA_FLUSH	0x00004000
#define	D_DMA_WIN	0x00008000

#define	D_INTR		0x00010000
#define	D_RMAP		0x00020000
#define	D_MAP_WIN	0x00040000
#define	D_UNMAP_WIN	0x00080000
#define	D_CHK_TAR	0x00100000
#define	D_SBUF		0x00200000
#define	D_INIT_CLD	0x00400000
#define	D_RM_CLD	0x00800000
#define	D_GET_REG	0x01000000
#define	D_XLATE_REG	0x02000000

#define	D_BYPASS	0x04000000

#define	D_ERR_INTR	0x08000000

#define	D_FAST_DVMA	0x10000000
#define	D_DMASYNC_FLUSH	0x20000000
#define	D_DMA_REQ	0x40000000

#define	D_CONT		0x80000000

#define	DBG(flag, psp, fmt)	\
	pci_debug(flag, psp, fmt, 0, 0, 0, 0, 0);
#define	DBG1(flag, psp, fmt, a1)	\
	pci_debug(flag, psp, fmt, (int)(a1), 0, 0, 0, 0);
#define	DBG2(flag, psp, fmt, a1, a2)	\
	pci_debug(flag, psp, fmt, (int)(a1), (int)(a2), 0, 0, 0);
#define	DBG3(flag, psp, fmt, a1, a2, a3)	\
	pci_debug(flag, psp, fmt, (int)(a1), (int)(a2), (int)(a3), 0, 0);
#define	DBG4(flag, psp, fmt, a1, a2, a3, a4)	\
	pci_debug(flag, psp, fmt, (int)(a1), (int)(a2), (int)(a3), \
		(int)(a4), 0);
#define	DBG5(flag, psp, fmt, a1, a2, a3, a4, a5)	\
	pci_debug(flag, psp, fmt, (int)(a1), (int)(a2), (int)(a3), \
		(int)(a4), (int)(a5));

static void pci_debug(u_int, pci_devstate_t *, char *, int, int, int, int, int);
static void dump_dma_handle(u_int, pci_devstate_t *, ddi_dma_impl_t *);
#else
#define	DBG(flag, psp, fmt)
#define	DBG1(flag, psp, fmt, a1)
#define	DBG2(flag, psp, fmt, a1, a2)
#define	DBG3(flag, psp, fmt, a1, a2, a3)
#define	DBG4(flag, psp, fmt, a1, a2, a3, a4)
#define	DBG5(flag, psp, fmt, a1, a2, a3, a4, a5)
#define	dump_dma_handle(flag, psp, h)
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_PCI_VAR_H */
