/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
 */
#ifndef _ASM_IA64_SN_PCI_PCIBR_PRIVATE_H
#define _ASM_IA64_SN_PCI_PCIBR_PRIVATE_H

/*
 * pcibr_private.h -- private definitions for pcibr
 * only the pcibr driver (and its closest friends)
 * should ever peek into this file.
 */

#include <linux/pci.h>
#include <asm/sn/pci/pcibr.h>
#include <asm/sn/pci/pciio_private.h>

/*
 * convenience typedefs
 */

typedef uint64_t pcibr_DMattr_t;
typedef uint32_t pcibr_ATEattr_t;

typedef struct pcibr_info_s *pcibr_info_t, **pcibr_info_h;
typedef struct pcibr_soft_s *pcibr_soft_t;
typedef struct pcibr_soft_slot_s *pcibr_soft_slot_t;
typedef struct pcibr_hints_s *pcibr_hints_t;
typedef struct pcibr_intr_list_s *pcibr_intr_list_t;
typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t;
typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t;

typedef volatile unsigned int *cfg_p;
typedef volatile bridgereg_t *reg_p;

/*
 * extern functions
 */
cfg_p pcibr_slot_config_addr(pcibr_soft_t, pciio_slot_t, int);
cfg_p pcibr_func_config_addr(pcibr_soft_t, pciio_bus_t bus, pciio_slot_t, pciio_function_t, int);
void pcibr_debug(uint32_t, vertex_hdl_t, char *, ...);
void pcibr_func_config_set(pcibr_soft_t, pciio_slot_t, pciio_function_t, int, unsigned);
/*
 * pcireg_ externs
 */

extern uint64_t		pcireg_id_get(pcibr_soft_t);
extern uint64_t		pcireg_bridge_id_get(void *);
extern uint64_t		pcireg_bus_err_get(pcibr_soft_t);
extern uint64_t		pcireg_control_get(pcibr_soft_t);
extern uint64_t		pcireg_bridge_control_get(void *);
extern void		pcireg_control_set(pcibr_soft_t, uint64_t);
extern void		pcireg_control_bit_clr(pcibr_soft_t, uint64_t);
extern void		pcireg_control_bit_set(pcibr_soft_t, uint64_t);
extern void		pcireg_req_timeout_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_dst_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_dst_target_id_get(pcibr_soft_t);
extern void		pcireg_intr_dst_target_id_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_dst_addr_get(pcibr_soft_t);
extern void		pcireg_intr_dst_addr_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_cmdword_err_get(pcibr_soft_t);
extern uint64_t		pcireg_llp_cfg_get(pcibr_soft_t);
extern void		pcireg_llp_cfg_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_tflush_get(pcibr_soft_t);
extern uint64_t		pcireg_linkside_err_get(pcibr_soft_t);
extern uint64_t		pcireg_resp_err_get(pcibr_soft_t);
extern uint64_t		pcireg_resp_err_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_resp_err_buf_get(pcibr_soft_t);
extern uint64_t		pcireg_resp_err_dev_get(pcibr_soft_t);
extern uint64_t		pcireg_linkside_err_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_dirmap_get(pcibr_soft_t);
extern void		pcireg_dirmap_set(pcibr_soft_t, uint64_t);
extern void		pcireg_dirmap_wid_set(pcibr_soft_t, uint64_t);
extern void		pcireg_dirmap_diroff_set(pcibr_soft_t, uint64_t);
extern void		pcireg_dirmap_add512_set(pcibr_soft_t);
extern void		pcireg_dirmap_add512_clr(pcibr_soft_t);
extern uint64_t		pcireg_map_fault_get(pcibr_soft_t);
extern uint64_t		pcireg_arbitration_get(pcibr_soft_t);
extern void		pcireg_arbitration_set(pcibr_soft_t, uint64_t);
extern void		pcireg_arbitration_bit_clr(pcibr_soft_t, uint64_t);
extern void		pcireg_arbitration_bit_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_parity_err_get(pcibr_soft_t);
extern uint64_t		pcireg_type1_cntr_get(pcibr_soft_t);
extern void		pcireg_type1_cntr_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_timeout_get(pcibr_soft_t);
extern void		pcireg_timeout_set(pcibr_soft_t, uint64_t);
extern void		pcireg_timeout_bit_clr(pcibr_soft_t, uint64_t);
extern void		pcireg_timeout_bit_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_pci_bus_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_pci_bus_addr_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_intr_status_get(pcibr_soft_t);
extern uint64_t		pcireg_intr_enable_get(pcibr_soft_t);
extern void		pcireg_intr_enable_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_enable_bit_clr(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_enable_bit_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_reset_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_reset_bit_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_mode_get(pcibr_soft_t);
extern void		pcireg_intr_mode_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_mode_bit_clr(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_device_get(pcibr_soft_t);
extern void		pcireg_intr_device_set(pcibr_soft_t, uint64_t);
extern void		pcireg_intr_device_bit_set(pcibr_soft_t, uint64_t);
extern void		pcireg_bridge_intr_device_bit_set(void *, uint64_t);
extern void		pcireg_intr_device_bit_clr(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_host_err_get(pcibr_soft_t);
extern void		pcireg_intr_host_err_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_intr_addr_get(pcibr_soft_t, int);
extern void		pcireg_intr_addr_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_bridge_intr_addr_set(void *, int, uint64_t);
extern void *		pcireg_intr_addr_addr(pcibr_soft_t, int);
extern void		pcireg_intr_addr_vect_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_bridge_intr_addr_vect_set(void *, int, uint64_t);
extern uint64_t		pcireg_intr_addr_addr_get(pcibr_soft_t, int);
extern void		pcireg_intr_addr_addr_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_bridge_intr_addr_addr_set(void *, int, uint64_t);
extern uint64_t		pcireg_intr_view_get(pcibr_soft_t);
extern uint64_t		pcireg_intr_multiple_get(pcibr_soft_t);
extern void		pcireg_force_always_set(pcibr_soft_t, int);
extern void *		pcireg_bridge_force_always_addr_get(void *, int);
extern void *		pcireg_force_always_addr_get(pcibr_soft_t, int);
extern void		pcireg_force_intr_set(pcibr_soft_t, int);
extern uint64_t		pcireg_device_get(pcibr_soft_t, int);
extern void		pcireg_device_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_device_bit_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_device_bit_clr(pcibr_soft_t, int, uint64_t);
extern uint64_t		pcireg_rrb_get(pcibr_soft_t, int);
extern void		pcireg_rrb_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_rrb_bit_set(pcibr_soft_t, int, uint64_t);
extern void		pcireg_rrb_bit_clr(pcibr_soft_t, int, uint64_t);
extern uint64_t		pcireg_rrb_status_get(pcibr_soft_t);
extern void		pcireg_rrb_clear_set(pcibr_soft_t, uint64_t);
extern uint64_t		pcireg_wrb_flush_get(pcibr_soft_t, int);
extern uint64_t		pcireg_pcix_bus_err_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_bus_err_attr_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_bus_err_data_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_req_err_attr_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_req_err_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_pio_split_addr_get(pcibr_soft_t);
extern uint64_t		pcireg_pcix_pio_split_attr_get(pcibr_soft_t);
extern cfg_p		pcireg_type1_cfg_addr(pcibr_soft_t, pciio_function_t,
					      int);
extern cfg_p		pcireg_type0_cfg_addr(pcibr_soft_t, pciio_slot_t,
					      pciio_function_t, int);
extern bridge_ate_t	pcireg_int_ate_get(pcibr_soft_t, int);
extern void		pcireg_int_ate_set(pcibr_soft_t, int, bridge_ate_t);
extern bridge_ate_p	pcireg_int_ate_addr(pcibr_soft_t, int);

extern uint64_t		pcireg_speed_get(pcibr_soft_t);
extern uint64_t		pcireg_mode_get(pcibr_soft_t);

/*
 * PCIBR_DEBUG() macro and debug bitmask defines
 */
/* low freqency debug events (ie. initialization, resource allocation,...) */
#define PCIBR_DEBUG_INIT	0x00000001  /* bridge init */
#define PCIBR_DEBUG_HINTS	0x00000002  /* bridge hints */
#define PCIBR_DEBUG_ATTACH	0x00000004  /* bridge attach */
#define PCIBR_DEBUG_DETACH	0x00000008  /* bridge detach */
#define PCIBR_DEBUG_ATE		0x00000010  /* bridge ATE allocation */
#define PCIBR_DEBUG_RRB		0x00000020  /* bridge RRB allocation */
#define PCIBR_DEBUG_RBAR	0x00000040  /* bridge RBAR allocation */
#define PCIBR_DEBUG_PROBE	0x00000080  /* bridge device probing */
#define PCIBR_DEBUG_INTR_ERROR  0x00000100  /* bridge error interrupt */
#define PCIBR_DEBUG_ERROR_HDLR  0x00000200  /* bridge error handler */
#define PCIBR_DEBUG_CONFIG	0x00000400  /* device's config space */
#define PCIBR_DEBUG_BAR		0x00000800  /* device's BAR allocations */
#define PCIBR_DEBUG_INTR_ALLOC	0x00001000  /* device's intr allocation */
#define PCIBR_DEBUG_DEV_ATTACH	0x00002000  /* device's attach */
#define PCIBR_DEBUG_DEV_DETACH	0x00004000  /* device's detach */
#define PCIBR_DEBUG_HOTPLUG	0x00008000

/* high freqency debug events (ie. map allocation, direct translation,...) */
#define PCIBR_DEBUG_DEVREG	0x04000000  /* bridges device reg sets */
#define PCIBR_DEBUG_PIOMAP	0x08000000  /* pcibr_piomap */
#define PCIBR_DEBUG_PIODIR	0x10000000  /* pcibr_piotrans */
#define PCIBR_DEBUG_DMAMAP	0x20000000  /* pcibr_dmamap */
#define PCIBR_DEBUG_DMADIR	0x40000000  /* pcibr_dmatrans */
#define PCIBR_DEBUG_INTR	0x80000000  /* interrupts */

extern char	 *pcibr_debug_module;
extern int	  pcibr_debug_widget;
extern int	  pcibr_debug_slot;
extern uint32_t pcibr_debug_mask;

/* For low frequency events (ie. initialization, resource allocation,...) */
#define PCIBR_DEBUG_ALWAYS(args) pcibr_debug args ;

/* XXX: habeck: maybe make PCIBR_DEBUG() always available?  Even in non-
 * debug kernels?  If tracing isn't enabled (i.e pcibr_debug_mask isn't
 * set, then the overhead for this macro is just an extra 'if' check.
 */
/* For high frequency events (ie. map allocation, direct translation,...) */
#if DEBUG
#define PCIBR_DEBUG(args) PCIBR_DEBUG_ALWAYS(args)
#else	/* DEBUG */
#define PCIBR_DEBUG(args)
#endif	/* DEBUG */

/*
 * Bridge sets up PIO using this information.
 */
struct pcibr_piomap_s {
    struct pciio_piomap_s   bp_pp;	/* generic stuff */

#define	bp_flags	bp_pp.pp_flags	/* PCIBR_PIOMAP flags */
#define	bp_dev		bp_pp.pp_dev	/* associated pci card */
#define	bp_slot		bp_pp.pp_slot	/* which slot the card is in */
#define	bp_space	bp_pp.pp_space	/* which address space */
#define	bp_pciaddr	bp_pp.pp_pciaddr	/* starting offset of mapping */
#define	bp_mapsz	bp_pp.pp_mapsz	/* size of this mapping */
#define	bp_kvaddr	bp_pp.pp_kvaddr	/* kernel virtual address to use */

    iopaddr_t               bp_xtalk_addr;	/* corresponding xtalk address */
    xtalk_piomap_t          bp_xtalk_pio;	/* corresponding xtalk resource */
    pcibr_piomap_t	    bp_next;	/* Next piomap on the list */
    pcibr_soft_t	    bp_soft;	/* backpointer to bridge soft data */
    atomic_t		    bp_toc;	/* PCI timeout counter */

};

/*
 * Bridge sets up DMA using this information.
 */
struct pcibr_dmamap_s {
    struct pciio_dmamap_s   bd_pd;
#define	bd_flags	bd_pd.pd_flags	/* PCIBR_DMAMAP flags */
#define	bd_dev		bd_pd.pd_dev	/* associated pci card */
#define	bd_slot		bd_pd.pd_slot	/* which slot the card is in */
    struct pcibr_soft_s    *bd_soft;	/* pcibr soft state backptr */
    xtalk_dmamap_t          bd_xtalk;	/* associated xtalk resources */

    size_t                  bd_max_size;	/* maximum size of mapping */
    xwidgetnum_t            bd_xio_port;	/* target XIO port */
    iopaddr_t               bd_xio_addr;	/* target XIO address */
    iopaddr_t               bd_pci_addr;	/* via PCI address */

    int                     bd_ate_index;	/* Address Translation Entry Index */
    int                     bd_ate_count;	/* number of ATE's allocated */
    bridge_ate_p            bd_ate_ptr;		/* where to write first ATE */
    bridge_ate_t            bd_ate_proto;	/* prototype ATE (for xioaddr=0) */
    bridge_ate_t            bd_ate_prime;	/* value of 1st ATE written */
    dma_addr_t		    bd_dma_addr;	/* Linux dma handle */
    struct resource	    resource;
};

#define	IBUFSIZE	5		/* size of circular buffer (holds 4) */

/*
 * Circular buffer used for interrupt processing
 */
struct pcibr_intr_cbuf_s {
    spinlock_t		ib_lock;		/* cbuf 'put' lock */
    int			ib_in;			/* index of next free entry */
    int			ib_out;			/* index of next full entry */
    pcibr_intr_wrap_t   ib_cbuf[IBUFSIZE];	/* circular buffer of wrap  */
};

/*
 * Bridge sets up interrupts using this information.
 */

struct pcibr_intr_s {
    struct pciio_intr_s     bi_pi;
#define	bi_flags	bi_pi.pi_flags	/* PCIBR_INTR flags */
#define	bi_dev		bi_pi.pi_dev	/* associated pci card */
#define	bi_lines	bi_pi.pi_lines	/* which PCI interrupt line(s) */
#define	bi_func		bi_pi.pi_func	/* handler function (when connected) */
#define	bi_arg		bi_pi.pi_arg	/* handler parameter (when connected) */
#define bi_mustruncpu	bi_pi.pi_mustruncpu /* Where we must run. */
#define bi_irq		bi_pi.pi_irq	/* IRQ assigned. */
#define bi_cpu		bi_pi.pi_cpu	/* cpu assigned. */
    unsigned int                bi_ibits;	/* which Bridge interrupt bit(s) */
    pcibr_soft_t            bi_soft;	/* shortcut to soft info */
    struct pcibr_intr_cbuf_s bi_ibuf;	/* circular buffer of wrap ptrs */
    unsigned		bi_last_intr;	/* For Shub lb lost intr. bug */
};


/* 
 * PCIBR_INFO_SLOT_GET_EXT returns the external slot number that the card
 * resides in.  (i.e the slot number silk screened on the back of the I/O 
 * brick).  PCIBR_INFO_SLOT_GET_INT returns the internal slot (or device)
 * number used by the pcibr code to represent that external slot (i.e to 
 * set bit patterns in BRIDGE/PIC registers to represent the device, or to
 * offset into an array, or ...).
 *
 * In BRIDGE and XBRIDGE the external slot and internal device numbering 
 * are the same.  (0->0, 1->1, 2->2,... 7->7)  BUT in the PIC the external
 * slot number is always 1 greater than the internal device number (1->0, 
 * 2->1, 3->2, 4->3).  This is due to the fact that the PCI-X spec requires
 * that the 'bridge' (i.e PIC) be designated as 'device 0', thus external
 * slot numbering can't start at zero.
 *
 * PCIBR_DEVICE_TO_SLOT converts an internal device number to an external
 * slot number.  NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE.
 *
 * PCIBR_SLOT_TO_DEVICE converts an external slot number to an internal
 * device number.  NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE.
 */
#define PCIBR_INFO_SLOT_GET_EXT(info)	    (((pcibr_info_t)info)->f_slot)
#define PCIBR_INFO_SLOT_GET_INT(info)	    (((pcibr_info_t)info)->f_dev)

#define PCIBR_DEVICE_TO_SLOT(pcibr_soft, dev_num) \
	(((dev_num) != PCIIO_SLOT_NONE) ? ((dev_num) + 1) : PCIIO_SLOT_NONE)

#define PCIBR_SLOT_TO_DEVICE(pcibr_soft, slot) \
        (((slot) != PCIIO_SLOT_NONE) ? ((slot) - 1) : PCIIO_SLOT_NONE)

/*
 * per-connect point pcibr data, including standard pciio data in-line:
 */
struct pcibr_info_s {
    struct pciio_info_s	    f_c;	/* MUST BE FIRST. */
#define	f_vertex	f_c.c_vertex	/* back pointer to vertex */
#define	f_bus		f_c.c_bus	/* which bus the card is in */
#define	f_slot		f_c.c_slot	/* which slot the card is in */
#define	f_func		f_c.c_func	/* which func (on multi-func cards) */
#define	f_vendor	f_c.c_vendor	/* PCI card "vendor" code */
#define	f_device	f_c.c_device	/* PCI card "device" code */
#define	f_master	f_c.c_master	/* PCI bus provider */
#define	f_mfast		f_c.c_mfast	/* cached fastinfo from c_master */
#define	f_pops		f_c.c_pops	/* cached provider from c_master */
#define	f_efunc		f_c.c_efunc	/* error handling function */
#define	f_einfo		f_c.c_einfo	/* first parameter for efunc */
#define	f_window	f_c.c_window	/* state of BASE regs */
#define	f_rwindow	f_c.c_rwindow	/* expansion ROM BASE regs */
#define	f_rbase		f_c.c_rbase	/* expansion ROM base */
#define	f_rsize		f_c.c_rsize	/* expansion ROM size */
#define	f_piospace	f_c.c_piospace	/* additional I/O spaces allocated */

    /* pcibr-specific connection state */
    int			    f_ibit[4];	/* Bridge bit for each INTx */
    pcibr_piomap_t	    f_piomap;
    int                     f_att_det_error;
    pciio_slot_t	    f_dev;	/* which device the card represents */
    cap_pcix_type0_t	   *f_pcix_cap;	/* pointer to the pcix capability */
};

/* =====================================================================
 *          Shared Interrupt Information
 */

struct pcibr_intr_list_s {
    pcibr_intr_list_t       il_next;
    pcibr_intr_t            il_intr;
    pcibr_soft_t	    il_soft;
    pciio_slot_t	    il_slot;
};

/* =====================================================================
 *          Interrupt Wrapper Data
 */
struct pcibr_intr_wrap_s {
    pcibr_soft_t            iw_soft;	/* which bridge */
    volatile bridgereg_t   *iw_stat;	/* ptr to b_int_status */
    bridgereg_t             iw_ibit;	/* bit in b_int_status */
    pcibr_intr_list_t       iw_list;	/* ghostbusters! */
    int			    iw_hdlrcnt;	/* running handler count */
    int			    iw_shared;  /* if Bridge bit is shared */
    int			    iw_connected; /* if already connected */
};

#define	PCIBR_ISR_ERR_START		8
#define PCIBR_ISR_MAX_ERRS_BRIDGE 	32
#define PCIBR_ISR_MAX_ERRS_PIC		45
#define PCIBR_ISR_MAX_ERRS	PCIBR_ISR_MAX_ERRS_PIC

/*
 * PCI Base Address Register window allocation constants.
 * To reduce the size of the internal resource mapping structures, do
 * not use the entire PCI bus I/O address space
 */ 
#define PCIBR_BUS_IO_BASE      0x200000
#define PCIBR_BUS_IO_MAX       0x0FFFFFFF
#define PCIBR_BUS_IO_PAGE      0x100000

#define PCIBR_BUS_SWIN_BASE    PAGE_SIZE
#define PCIBR_BUS_SWIN_MAX     0x000FFFFF
#define PCIBR_BUS_SWIN_PAGE    PAGE_SIZE

#define PCIBR_BUS_MEM_BASE     0x200000
#define PCIBR_BUS_MEM_MAX      0x3FFFFFFF
#define PCIBR_BUS_MEM_PAGE     0x100000

/* defines for pcibr_soft_s->bs_bridge_type */
#define PCIBR_BRIDGETYPE_PIC		2
#define IS_PIC_BUSNUM_SOFT(ps, bus)	((ps)->bs_busnum == (bus))

/*
 * Runtime checks for workarounds.
 */
#define PCIBR_WAR_ENABLED(pv, pcibr_soft) \
	((1 << XWIDGET_PART_REV_NUM_REV(pcibr_soft->bs_rev_num)) & pv)

/* defines for pcibr_soft_s->bs_bridge_mode */
#define PCIBR_BRIDGEMODE_PCI_33		0x0
#define PCIBR_BRIDGEMODE_PCI_66		0x2
#define PCIBR_BRIDGEMODE_PCIX_66	0x3
#define PCIBR_BRIDGEMODE_PCIX_100	0x5
#define PCIBR_BRIDGEMODE_PCIX_133	0x7
#define BUSSPEED_MASK			0x6
#define BUSTYPE_MASK			0x1

#define IS_PCI(ps)	(!IS_PCIX(ps))
#define IS_PCIX(ps)	((ps)->bs_bridge_mode & BUSTYPE_MASK)

#define IS_33MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_33)
#define IS_66MHZ(ps)	(((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_66) || \
			 ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_66))
#define IS_100MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_100)
#define IS_133MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_133)


/* Number of PCI slots.   NOTE: this works as long as the first slot
 * is zero.  Otherwise use ((ps->bs_max_slot+1) - ps->bs_min_slot)
 */
#define PCIBR_NUM_SLOTS(ps) (ps->bs_max_slot+1)

/* =====================================================================
 *            Bridge Device State structure
 *
 *      one instance of this structure is kept for each
 *      Bridge ASIC in the system.
 */

struct pcibr_soft_s {
    vertex_hdl_t          bs_conn;		/* xtalk connection point */
    vertex_hdl_t          bs_vhdl;		/* vertex owned by pcibr */
    uint64_t                bs_int_enable;	/* Mask of enabled intrs */
    void               *bs_base;		/* PIO pointer to Bridge chip */
    char                   *bs_name;		/* hw graph name */
    char		    bs_asic_name[16];	/* ASIC name */
    xwidgetnum_t            bs_xid;		/* Bridge's xtalk ID number */
    vertex_hdl_t          bs_master;		/* xtalk master vertex */
    xwidgetnum_t            bs_mxid;		/* master's xtalk ID number */
    pciio_slot_t            bs_first_slot;      /* first existing slot */
    pciio_slot_t            bs_last_slot;       /* last existing slot */
    pciio_slot_t            bs_last_reset;      /* last slot to reset */
    uint32_t		    bs_unused_slot;	/* unavailable slots bitmask */
    pciio_slot_t	    bs_min_slot;	/* lowest possible slot */
    pciio_slot_t	    bs_max_slot;	/* highest possible slot */
    pcibr_soft_t	    bs_peers_soft;	/* PICs other bus's soft */
    int			    bs_busnum;		/* PIC has two pci busses */

    iopaddr_t               bs_dir_xbase;	/* xtalk address for 32-bit PCI direct map */
    xwidgetnum_t	    bs_dir_xport;	/* xtalk port for 32-bit PCI direct map */

    struct resource	    bs_int_ate_resource;/* root resource for internal ATEs */
    struct resource	    bs_ext_ate_resource;/* root resource for external ATEs */
    void	 	    *bs_allocated_ate_res;/* resource struct allocated */
    short		    bs_int_ate_size;	/* number of internal ates */
    short		    bs_bridge_type;	/* see defines above */
    short		    bs_bridge_mode;	/* see defines above */

    int                     bs_rev_num;	/* revision number of Bridge */

    /* bs_dma_flags are the forced dma flags used on all DMAs. Used for
     * working around ASIC rev issues and protocol specific requirements
     */
    unsigned int            bs_dma_flags;	/* forced DMA flags */

    nasid_t		    bs_nasid;		/* nasid this bus is on */
    moduleid_t		    bs_moduleid;	/* io brick moduleid */
    short		    bs_bricktype;	/* io brick type */

    /*
     * Lock used primarily to get mutual exclusion while managing any
     * bridge resources..
     */
    spinlock_t              bs_lock;
    
    vertex_hdl_t	    bs_noslot_conn;	/* NO-SLOT connection point */
    pcibr_info_t	    bs_noslot_info;

#ifdef CONFIG_HOTPLUG_PCI_SGI
    /* Linux PCI bus structure pointer */
    struct pci_bus         *bs_pci_bus;
#endif

    struct pcibr_soft_slot_s {
	/* information we keep about each CFG slot */

	/* some devices (ioc3 in non-slotted
	 * configurations, sometimes) make use
	 * of more than one REQ/GNT/INT* signal
	 * sets. The slot corresponding to the
	 * IDSEL that the device responds to is
	 * called the host slot; the slot
	 * numbers that the device is stealing
	 * REQ/GNT/INT bits from are known as
	 * the guest slots.
	 */
	int                     has_host;
	pciio_slot_t            host_slot;
	vertex_hdl_t		slot_conn;

#ifdef CONFIG_HOTPLUG_PCI_SGI
        /* PCI Hot-Plug status word */
        int 			slot_status;

	/* PCI Hot-Plug core structure pointer */
	struct hotplug_slot    *bss_hotplug_slot;
#endif	/* CONFIG_HOTPLUG_PCI_SGI */

	/* Potentially several connection points
	 * for this slot. bss_ninfo is how many,
	 * and bss_infos is a pointer to
	 * an array pcibr_info_t values (which are
	 * pointers to pcibr_info structs, stored
	 * as device_info in connection ponts).
	 */
	int			bss_ninfo;
	pcibr_info_h	        bss_infos;

	/* Temporary Compatibility Macros, for
	 * stuff that has moved out of bs_slot
	 * and into the info structure. These
	 * will go away when their users have
	 * converted over to multifunction-
	 * friendly use of bss_{ninfo,infos}.
	 */
#define	bss_vendor_id	bss_infos[0]->f_vendor
#define	bss_device_id	bss_infos[0]->f_device
#define	bss_window	bss_infos[0]->f_window
#define	bssw_space	w_space
#define	bssw_base	w_base
#define	bssw_size	w_size

	/* Where is DevIO(x) pointing? */
	/* bssd_space is NONE if it is not assigned. */
	struct {
	    pciio_space_t           bssd_space;
	    iopaddr_t               bssd_base;
            int                     bssd_ref_cnt;
	} bss_devio;

	/* Shadow value for Device(x) register,
	 * so we don't have to go to the chip.
	 */
	uint64_t		bss_device;

	/* Number of sets on GBR/REALTIME bit outstanding
	 * Used by Priority I/O for tracking reservations
	 */
	int                     bss_pri_uctr;

	/* Number of "uses" of PMU, 32-bit direct,
	 * and 64-bit direct DMA (0:none, <0: trans,
	 * >0: how many dmamaps). Device(x) bits
	 * controlling attribute of each kind of
	 * channel can't be changed by dmamap_alloc
	 * or dmatrans if the controlling counter
	 * is nonzero. dmatrans is forever.
	 */
	int                     bss_pmu_uctr;
	int                     bss_d32_uctr;
	int                     bss_d64_uctr;

	/* When the contents of mapping configuration
	 * information is locked down by dmatrans,
	 * repeated checks of the same flags should
	 * be shortcircuited for efficiency.
	 */
	iopaddr_t		bss_d64_base;
	unsigned		bss_d64_flags;
	iopaddr_t		bss_d32_base;
	unsigned		bss_d32_flags;
    } bs_slot[8];

    pcibr_intr_bits_f	       *bs_intr_bits;

    /* PIC PCI-X Read Buffer Management :
     * bs_pcix_num_funcs: the total number of PCI-X functions
     *  on the bus
     * bs_pcix_split_tot: total number of outstanding split
     *  transactions requested by all functions on the bus
     * bs_pcix_rbar_percent_allowed: the percentage of the
     *  total number of buffers a function requested that are 
     *  available to it, not including the 1 RBAR guaranteed 
     *  to it.
     * bs_pcix_rbar_inuse: number of RBARs in use.
     * bs_pcix_rbar_avail: number of RBARs available.  NOTE:
     *  this value can go negative if we oversubscribe the 
     *  RBARs.  (i.e.  We have 16 RBARs but 17 functions).
     */
    int			    bs_pcix_num_funcs;
    int			    bs_pcix_split_tot;
    int			    bs_pcix_rbar_percent_allowed;

    int			    bs_pcix_rbar_inuse;
    int			    bs_pcix_rbar_avail;


    /* RRB MANAGEMENT
     * bs_rrb_fixed: bitmap of slots whose RRB
     *	allocations we should not "automatically" change
     * bs_rrb_avail: number of RRBs that have not
     *  been allocated or reserved for {even,odd} slots
     * bs_rrb_res: number of RRBs currently reserved for the
     *	use of the index slot number
     * bs_rrb_res_dflt: number of RRBs reserved at boot
     *  time for the use of the index slot number
     * bs_rrb_valid: number of RRBs currently marked valid
     *	for the indexed slot/vchan number; array[slot][vchan]
     * bs_rrb_valid_dflt: number of RRBs marked valid at boot
     *  time for the indexed slot/vchan number; array[slot][vchan]
     */
    int                     bs_rrb_fixed;
    int			    bs_rrb_avail[2];
    int			    bs_rrb_res[8];
    int			    bs_rrb_res_dflt[8];
    int			    bs_rrb_valid[8][4];
    int			    bs_rrb_valid_dflt[8][4];
    struct {
	/* Each Bridge interrupt bit has a single XIO
	 * interrupt channel allocated.
	 */
	xtalk_intr_t            bsi_xtalk_intr;
	/*
	 * A wrapper structure is associated with each
	 * Bridge interrupt bit.
	 */
	struct pcibr_intr_wrap_s  bsi_pcibr_intr_wrap;
	/* The bus and interrupt bit, used for pcibr_setpciint().
	 * The pci busnum is bit3, int_bits bit2:0
	 */
	uint32_t		bsi_int_bit;

    } bs_intr[8];

    xtalk_intr_t		bsi_err_intr;

    /*
     * We stash away some information in this structure on getting
     * an error interrupt. This information is used during PIO read/
     * write error handling.
     *
     * As it stands now, we do not re-enable the error interrupt
     * till the error is resolved. Error resolution happens either at
     * bus error time for PIO Read errors (~100 microseconds), or at
     * the scheduled timeout time for PIO write errors (~milliseconds).
     * If this delay causes problems, we may need to move towards
     * a different scheme..
     *
     * Note that there is no locking while looking at this data structure.
     * There should not be any race between bus error code and
     * error interrupt code.. will look into this if needed.
     *
     * NOTE: The above discussion of error interrupt processing is
     *       no longer true. Whether it should again be true, is
     *       being looked into.
     */
    struct br_errintr_info {
	int                     bserr_toutcnt;
	iopaddr_t               bserr_addr;	/* Address where error occured */
	uint64_t		bserr_intstat;	/* interrupts active at error dump */
    } bs_errinfo;

    /*
     * PCI Bus Space allocation data structure.
     *
     * The resource mapping functions rmalloc() and rmfree() are used
     * to manage the PCI bus I/O, small window, and memory  address 
     * spaces.
     *
     * This info is used to assign PCI bus space addresses to cards
     * via their BARs and to the callers of the pcibr_piospace_alloc()
     * interface.
     *
     * Users of the pcibr_piospace_alloc() interface, such as the VME
     * Universe chip, need PCI bus space that is not acquired by BARs.
     * Most of these users need "large" amounts of PIO space (typically
     * in Megabytes), and they generally tend to take once and never
     * release. 
     */
    struct pciio_win_map_s	bs_io_win_map;	/* I/O addr space */
    struct pciio_win_map_s	bs_swin_map;	/* Small window addr space */
    struct pciio_win_map_s	bs_mem_win_map;	/* Memory addr space */

    struct resource		bs_io_win_root_resource; /* I/O addr space */
    struct resource		bs_swin_root_resource; /* Small window addr space */
    struct resource		bs_mem_win_root_resource; /* Memory addr space */

    int                   bs_bus_addr_status;    /* Bus space status */

#define PCIBR_BUS_ADDR_MEM_FREED       1  /* Reserved PROM mem addr freed */
#define PCIBR_BUS_ADDR_IO_FREED        2  /* Reserved PROM I/O addr freed */

    struct bs_errintr_stat_s {
	uint32_t		bs_errcount_total;
	uint32_t		bs_lasterr_timestamp;
	uint32_t		bs_lasterr_snapshot;
    } bs_errintr_stat[PCIBR_ISR_MAX_ERRS];

    /*
     * Bridge-wide endianness control for
     * large-window PIO mappings
     *
     * These fields are set to PCIIO_BYTE_SWAP
     * or PCIIO_WORD_VALUES once the swapper
     * has been configured, one way or the other,
     * for the direct windows. If they are zero,
     * nobody has a PIO mapping through that window,
     * and the swapper can be set either way.
     */
    unsigned		bs_pio_end_io;
    unsigned		bs_pio_end_mem;
};

#define	PCIBR_ERRTIME_THRESHOLD		(100)
#define	PCIBR_ERRRATE_THRESHOLD		(100)

/*
 * pcibr will respond to hints dropped in its vertex
 * using the following structure.
 */
struct pcibr_hints_s {
    /* ph_host_slot is actually +1 so "0" means "no host" */
    pciio_slot_t            ph_host_slot[8];	/* REQ/GNT/INT in use by ... */
    unsigned int            ph_rrb_fixed;	/* do not change RRB allocations */
    unsigned int            ph_hands_off;	/* prevent further pcibr operations */
    rrb_alloc_funct_t       rrb_alloc_funct;	/* do dynamic rrb allocation */
    pcibr_intr_bits_f	   *ph_intr_bits;	/* map PCI INT[ABCD] to Bridge Int(n) */
};

/*
 * Number of bridge non-fatal error interrupts we can see before
 * we decide to disable that interrupt.
 */
#define	PCIBR_ERRINTR_DISABLE_LEVEL	10000

/* =====================================================================
 *    Bridge (pcibr) state management functions
 *
 *      pcibr_soft_get is here because we do it in a lot
 *      of places and I want to make sure they all stay
 *      in step with each other.
 *
 *      pcibr_soft_set is here because I want it to be
 *      closely associated with pcibr_soft_get, even
 *      though it is only called in one place.
 */

#define pcibr_soft_get(v)       ((pcibr_soft_t)hwgraph_fastinfo_get((v)))
#define pcibr_soft_set(v,i)     (hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)))

/*
 * Additional PIO spaces per slot are
 * recorded in this structure.
 */
struct pciio_piospace_s {
    pciio_piospace_t        next;	/* another space for this device */
    char                    free;	/* 1 if free, 0 if in use */
    pciio_space_t           space;	/* Which space is in use */
    iopaddr_t               start;	/* Starting address of the PIO space */
    size_t                  count;	/* size of PIO space */
};

/* 
 * pcibr_soft structure locking macros
 */
inline static unsigned long
pcibr_lock(pcibr_soft_t pcibr_soft)
{
        unsigned long flag;
        spin_lock_irqsave(&pcibr_soft->bs_lock, flag);
        return(flag);
}
#define pcibr_unlock(pcibr_soft, flag)  spin_unlock_irqrestore(&pcibr_soft->bs_lock, flag)

#define PCIBR_VALID_SLOT(ps, s)     (s < PCIBR_NUM_SLOTS(ps))
#define PCIBR_D64_BASE_UNSET    (0xFFFFFFFFFFFFFFFF)
#define PCIBR_D32_BASE_UNSET    (0xFFFFFFFF)
#define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev"

#define PCIBR_SOFT_LIST 1
#if PCIBR_SOFT_LIST
typedef struct pcibr_list_s *pcibr_list_p;
struct pcibr_list_s {
    pcibr_list_p            bl_next;
    pcibr_soft_t            bl_soft;
    vertex_hdl_t            bl_vhdl;
};
#endif /* PCIBR_SOFT_LIST */

/* Devices per widget: 2 buses, 2 slots per bus, 8 functions per slot. */
#define DEV_PER_WIDGET (2*2*8)

struct sn_flush_device_list {
	int bus;
	int slot;
	int pin;
	struct bar_list {
		unsigned long start;
		unsigned long end;
	} bar_list[PCI_ROM_RESOURCE];
	unsigned long force_int_addr;
	volatile unsigned long flush_addr;
	spinlock_t flush_lock;
};

struct sn_flush_nasid_entry  {
        struct sn_flush_device_list **widget_p;
        unsigned long        iio_itte[8];
};

#endif				/* _ASM_SN_PCI_PCIBR_PRIVATE_H */
