patch-2.4.21 linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c

Next file: linux-2.4.21/arch/ia64/sn/io/sn2/pciio.c
Previous file: linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
@@ -30,70 +31,90 @@
 #include <asm/sn/eeprom.h>
 #include <asm/sn/io.h>
 #include <asm/sn/sn_private.h>
+#include <asm/sn/ate_utils.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
 
 extern pcibr_info_t     pcibr_info_get(devfs_handle_t);
-extern int              pcibr_widget_to_bus(int);
+extern int              pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl);
 extern pcibr_info_t     pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
-extern void             pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
 extern int		pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
-#if 0
-int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-#endif
+extern int		pcibr_pcix_rbars_calc(pcibr_soft_t);
 
 int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
+int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,  pciio_slot_t slot);
 int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
 int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
-int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags);
+int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
+                 int drv_flags, char *l1_msg, int *sub_errorp);
 int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
-void		 pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
-extern uint64_t  do_pcibr_config_get(cfg_p, unsigned, unsigned);
+static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
+void pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
+iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, 
+                               pciio_space_t, int, int, int);
+void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t);
+cfg_p pcibr_find_capability(cfg_p, unsigned);
+extern uint64_t  do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
+void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); 
 
-#ifdef LATER
 int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
                 int drv_flags, char *l1_msg, int *sub_errorp);
-int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *);
-int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
-int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
-void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func,
-                 pcibr_slot_func_info_resp_t funcp);
+
 int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot,
                  pcibr_slot_info_resp_t respp);
-int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
-#endif	/* LATER */
 
 extern devfs_handle_t baseio_pci_vhdl;
 int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t);
 
+
 /* For now .... */
 /*
  * PCI Hot-Plug Capability Flags
+
  */
 #define D_PCI_HOT_PLUG_ATTACH  0x200  /* Driver supports PCI hot-plug attach */
 #define D_PCI_HOT_PLUG_DETACH  0x400  /* Driver supports PCI hot-plug detach */
 
 
+/* 
+ * PCI-X Max Outstanding Split Transactions translation array and Max Memory
+ * Read Byte Count translation array, as defined in the PCI-X Specification.
+ * Section 7.2.3 & 7.2.4 of PCI-X Specification - rev 1.0
+ */
+#define MAX_SPLIT_TABLE 8
+#define MAX_READCNT_TABLE 4
+int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32};
+int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 };
+
+
 /*==========================================================================
  *	BRIDGE PCI SLOT RELATED IOCTLs
  */
 
-#ifdef LATER
-
 /*
  * pcibr_slot_startup
  *	Software start-up the PCI slot.
  */
+
+#ifdef PIC_LATER
+
 int
 pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_up_resp_s    tmp_up_resp;
@@ -103,17 +124,22 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     /* Do not allow start-up of a slot in a shoehorn */
     if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
        return(PCI_SLOT_IN_SHOEHORN);
     }
  
     /* Check for the valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) {
         error = PCI_SLOT_ALREADY_UP;
@@ -132,9 +158,10 @@
 
     startup_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
     return(error);
 }
 
@@ -147,7 +174,7 @@
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t                      *bridge;
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_down_resp_s  tmp_down_resp;
@@ -158,10 +185,13 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     bridge = pcibr_soft->bs_base;
 
     /* Check for valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
     /* Do not allow shut-down of a slot in a shoehorn */
@@ -169,8 +199,10 @@
        return(PCI_SLOT_IN_SHOEHORN);
     }
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) ||
         ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) {
@@ -182,6 +214,13 @@
         goto shutdown_unlock;
     }
 
+    /* Do not allow a multi-function card to be hot-plug removed */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        tmp_down_resp.resp_sub_errno = EPERM;
+        error = PCI_MULTI_FUNC_ERR;
+        goto shutdown_copyout;
+    }
+
     /* Do not allow the last 33 MHz card to be removed */
     if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) ==
          BRIDGE_CTRL_BUS_SPEED_33) {
@@ -204,17 +243,22 @@
     strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE);
     tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0';
 
+    shutdown_copyout:
+
     if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) {
         return(EFAULT);
     }
 
     shutdown_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
+#endif
 
     return(error);
 }
+#endif	/* PIC_LATER */
 
 char *pci_space_name[] = {"NONE", 
 			  "ROM",
@@ -240,6 +284,7 @@
 {
     pcibr_info_t                 pcibr_info = pcibr_infoh[func];
     int                          win;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     funcp->resp_f_status = 0;
 
@@ -248,16 +293,19 @@
     }
 
     funcp->resp_f_status |= FUNC_IS_VALID;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
-
+#endif
     if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
         funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
     }
 
     funcp->resp_f_bus = pcibr_info->f_bus;
-    funcp->resp_f_slot = pcibr_info->f_slot;
+    funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info);
     funcp->resp_f_func = pcibr_info->f_func;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
+#endif
     funcp->resp_f_pops = pcibr_info->f_pops;
     funcp->resp_f_efunc = pcibr_info->f_efunc;
     funcp->resp_f_einfo = pcibr_info->f_einfo;
@@ -297,20 +345,29 @@
     reg_p                        b_respp;
     pcibr_slot_info_resp_t       slotp;
     pcibr_slot_func_info_resp_t  funcp;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
+    extern void snia_kmem_free(void *, int);
 
-    slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP);
+    slotp = snia_kmem_zalloc(sizeof(*slotp), 0);
     if (slotp == NULL) {
         return(ENOMEM);
     }
 
     pss = &pcibr_soft->bs_slot[slot];
 
+    slotp->resp_bs_bridge_mode = pcibr_soft->bs_bridge_mode;
+    slotp->resp_bs_bridge_type = pcibr_soft->bs_bridge_type;
+
     slotp->resp_has_host = pss->has_host;
     slotp->resp_host_slot = pss->host_slot;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
+#else
+    sprintf(slotp->resp_slot_conn_name, "%p", (void *)pss->slot_conn);
+#endif
     slotp->resp_slot_status = pss->slot_status;
 
-    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
+    slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl);
 
     if (is_sys_critical_vertex(pss->slot_conn)) {
         slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
@@ -342,9 +399,10 @@
     slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
     slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
 
-    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
-    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
-                                                      PCIBR_RRB_SLOT_VIRTUAL];
+    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot][VCHAN0];
+    slotp->resp_bs_rrb_valid_v1 = pcibr_soft->bs_rrb_valid[slot][VCHAN1];
+    slotp->resp_bs_rrb_valid_v2 = pcibr_soft->bs_rrb_valid[slot][VCHAN2];
+    slotp->resp_bs_rrb_valid_v3 = pcibr_soft->bs_rrb_valid[slot][VCHAN3];
     slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
 
     if (slot & 1) {
@@ -355,16 +413,21 @@
 
     slotp->resp_b_resp = *b_respp;
 
-    slotp->resp_b_wid_control = bridge->b_wid_control;
     slotp->resp_b_int_device = bridge->b_int_device;
-    slotp->resp_b_int_enable = bridge->b_int_enable;
-    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	slotp->resp_p_int_enable = bridge->p_int_enable_64;
+	slotp->resp_p_int_host = bridge->p_int_addr_64[slot];
+    } else {
+	slotp->resp_b_int_enable = bridge->b_int_enable;
+	slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+    }
 
     if (COPYOUT(slotp, respp, sizeof(*respp))) {
         return(EFAULT);
     }
 
-    kmem_free(slotp, sizeof(*slotp));
+    snia_kmem_free(slotp, sizeof(*slotp));
 
     return(0);
 }
@@ -395,19 +458,26 @@
 pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t            slot = reqp->req_slot;
+    pciio_slot_t            slot;
     pciio_slot_t            tmp_slot;
     pcibr_slot_info_resp_t  respp = reqp->req_respp.query;
     int                     size = reqp->req_size;
-    int                     error;
+    int                     error = 0;
 
     /* Make sure that we are dealing with a bridge device vertex */
     if (!pcibr_soft) {
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl,
+                "pcibr_slot_query: pcibr_soft=0x%x, slot=%d, reqp=0x%x\n",
+                pcibr_soft, slot, reqp));
+
     /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
+    if ((!PCIBR_VALID_SLOT(pcibr_soft, slot)) && (slot != PCIIO_SLOT_NONE)) {
         return(PCI_NOT_A_SLOT);
     }
 
@@ -422,32 +492,37 @@
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, slot, respp);
 
+#ifdef PIC_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         return(error);
     }
 
     /* Return information for all the slots */
-    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
+    for (tmp_slot = pcibr_soft->bs_min_slot; 
+		tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); tmp_slot++) {
 
         if (size < sizeof(*respp)) {
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
 
+#ifdef PCI_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         if (error) {
             return(error);
         }
@@ -458,60 +533,92 @@
 
     return(error);
 }
-#endif	/* LATER */
 
-/* FIXME: there should be a better way to do this.
- * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE
+#if 0
+/*
+ * pcibr_slot_reset
+ *	Reset the PCI device in the particular slot.
+ *
+ *      The Xbridge does not comply with the PCI Specification
+ *      when resetting an indiviaudl slot.  An individual slot is
+ *      is reset by toggling the slot's bit in the Xbridge Control
+ *      Register.  The Xbridge will assert the target slot's 
+ *      (non-bussed) RST signal, but does not assert the (bussed) 
+ *      REQ64 signal as required by the specification.   As
+ *      designed, the Xbridge cannot assert the REQ64 signal
+ *      becuase it may interfere with a bus transaction in progress.
+ *      The practical effects of this Xbridge implementation is
+ *      device dependent;  it probably will not adversely effect
+ *      32-bit cards, but may disable 64-bit data transfers by those
+ *      cards that normally support 64-bit data transfers.  
+ *
+ *      The Xbridge will assert REQ64 when all four slots are reset
+ *      by simultaneously toggling all four slot reset bits in the
+ *      Xbridge Control Register.  This is basically a PCI bus reset
+ *      and asserting the (bussed) REQ64 signal will not interfere
+ *      with any bus transactions in progress.
+ *
+ *      The Xbridge (and the SN0 Bridge) support resetting only
+ *      four PCI bus slots via the (X)bridge Control Register.
+ *
+ *      To reset an individual slot for the PCI Hot-Plug feature
+ *      use the L1 console commands to power-down and then 
+ *      power-up the slot, or use the kernel infrastructure
+ *      functions to power-down/up the slot when they are
+ *      implemented for SN1.
  */
+int
+pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
+{
+	pcibr_soft_t		 pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+	bridge_t		*bridge;
+	bridgereg_t		 ctrlreg,tmp;
+	volatile bridgereg_t	*wrb_flush;
 
-/* 
- * PCI_ADDR_SPACE_LIMITS_LOAD
- *	Gets the current values of 
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_LOAD()			\
-    pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base;	\
-    pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last;	\
-    pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base;	\
-    pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last;	\
-    pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base;	\
-    pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last;
-/*
- * PCI_ADDR_SPACE_LIMITS_STORE
- *	Sets the current values of
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_STORE()			\
-    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\
-    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\
-    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\
-    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\
-    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\
-    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
-
-#define PCI_ADDR_SPACE_LIMITS_PRINT()			\
-    printf("+++++++++++++++++++++++\n"			\
-	   "IO base 0x%x last 0x%x\n"			\
-	   "SWIN base 0x%x last 0x%x\n"			\
-	   "MEM base 0x%x last 0x%x\n"			\
-	   "+++++++++++++++++++++++\n",			\
-	   pcibr_soft->bs_spinfo.pci_io_base,		\
-	   pcibr_soft->bs_spinfo.pci_io_last,		\
-	   pcibr_soft->bs_spinfo.pci_swin_base,		\
-	   pcibr_soft->bs_spinfo.pci_swin_last,		\
-	   pcibr_soft->bs_spinfo.pci_mem_base,		\
-	   pcibr_soft->bs_spinfo.pci_mem_last);
+	if (!pcibr_soft)
+		return(EINVAL);
+
+	if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+		return(EINVAL);
+
+	/* Enable the DMA operations from this device of the xtalk widget
+	 * (PCI host bridge in this case).
+	 */
+	xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot);
+
+	/* Set the reset slot bit in the bridge's wid control register
+	 * to reset the PCI slot 
+	 */
+	bridge = pcibr_soft->bs_base;
+
+	/* Read the bridge widget control and clear out the reset pin
+	 * bit for the corresponding slot. 
+	 */
+	tmp = ctrlreg = bridge->b_wid_control;
+
+	tmp &= ~BRIDGE_CTRL_RST_PIN(slot); 
+
+	bridge->b_wid_control = tmp;
+	tmp = bridge->b_wid_control;
+
+	/* Restore the old control register back.
+	 * NOTE : PCI card gets reset when the reset pin bit
+	 * changes from 0 (set above) to 1 (going to be set now).
+	 */
+
+	bridge->b_wid_control = ctrlreg;
 
+	/* Flush the write buffers if any !! */
+	wrb_flush = &(bridge->b_wr_req_buf[slot].reg);
+	while (*wrb_flush);
+
+	return(0);
+}
+#endif
+
+#define PROBE_LOCK 0	/* FIXME: we're attempting to lock around accesses
+			 * to b_int_enable.   This hangs pcibr_probe_slot()
+			 */
 
 /*
  * pcibr_slot_info_init
@@ -534,12 +641,12 @@
     pciio_vendor_id_t       vendor;
     pciio_device_id_t       device;
     unsigned                htype;
+    unsigned                lt_time;
+    int                     nbars;
     cfg_p                   wptr;
+    cfg_p                   pcix_cap;
     int                     win;
     pciio_space_t           space;
-    iopaddr_t		    pci_io_fb,	pci_io_fl;
-    iopaddr_t		    pci_lo_fb,  pci_lo_fl;
-    iopaddr_t		    pci_hi_fb,  pci_hi_fl;
     int			    nfunc;
     pciio_function_t	    rfunc;
     int			    func;
@@ -552,7 +659,7 @@
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization
@@ -566,28 +673,35 @@
     if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
         return(EPERM);
 
-    /* Load the current values of allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
-    
     /* Try to read the device-id/vendor-id from the config space */
-    cfgw = bridge->b_type0_cfg_dev[slot].l;
+    cfgw = pcibr_slot_config_addr(bridge, slot, 0);
 
+#if PROBE_LOCK
+    s = pcibr_lock(pcibr_soft);
+#endif
     if (pcibr_probe_slot(bridge, cfgw, &idword)) 
 	return(ENODEV);
+#if PROBE_LOCK
+    pcibr_unlock(pcibr_soft, s);
+#endif
 
     slotp = &pcibr_soft->bs_slot[slot];
     slotp->slot_status |= SLOT_POWER_UP;
 
     vendor = 0xFFFF & idword;
+    device = 0xFFFF & (idword >> 16);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl,
+		"pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device));
+
     /* If the vendor id is not valid then the slot is not populated
      * and we are done.
      */
     if (vendor == 0xFFFF) 
 	return(ENODEV);			
     
-    device = 0xFFFF & (idword >> 16);
-    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
-
+    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
     nfunc = 1;
     rfunc = PCIIO_FUNC_NONE;
     pfail = 0;
@@ -599,11 +713,17 @@
 
     if (htype & 0x80) {		/* MULTIFUNCTION */
 	for (func = 1; func < 8; ++func) {
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+#if PROBE_LOCK
+            s = pcibr_lock(pcibr_soft);
+#endif
 	    if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {
 		pfail |= 1 << func;
 		continue;
 	    }
+#if PROBE_LOCK
+            pcibr_unlock(pcibr_soft, s);
+#endif
 	    vendor = 0xFFFF & idwords[func];
 	    if (vendor == 0xFFFF) {
 		pfail |= 1 << func;
@@ -612,7 +732,7 @@
 	    nfunc = func + 1;
 	    rfunc = 0;
 	}
-	cfgw = bridge->b_type0_cfg_dev[slot].l;
+        cfgw = pcibr_slot_config_addr(bridge, slot, 0);
     }
     NEWA(pcibr_infoh, nfunc);
     
@@ -627,39 +747,162 @@
 		continue;
 	    
 	    idword = idwords[func];
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	    
 	    device = 0xFFFF & (idword >> 16);
-	    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
+	    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
 	    rfunc = func;
 	}
 	htype &= 0x7f;
 	if (htype != 0x00) {
-	    printk(KERN_WARNING  "%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
+	    printk(KERN_WARNING 
+		"%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
 		    pcibr_soft->bs_name, slot, func, htype);
-	    continue;
+	    nbars = 2;
+	} else {
+	    nbars = PCI_CFG_BASE_ADDRS;
+	}
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw));
+
+#ifdef PIC_LATER
+        /*
+         * Check for a Quad ATM PCI "card" and return all the PCI bus
+         * memory and I/O space.  This will work-around an apparent
+         * hardware problem with the Quad ATM XIO card handling large
+         * PIO addresses.  Releasing all the space for use by the card
+         * will lower the PIO addresses with the PCI bus address space.
+         * This is OK since the PROM did not assign any BAR addresses. 
+         *
+         * Only release all the PCI bus addresses once.
+         *
+         */
+        if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) {
+            iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;
+            int                     prom_base_size = 0x1000000;
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_mem_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED;
+            }
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_io_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED;
+            }
+        }
+#endif	/* PIC_LATER */
+
+	/* 
+	 * If the latency timer has already been set, by prom or by the
+	 * card itself, use that value.  Otherwise look at the device's
+	 * 'min_gnt' and attempt to calculate a latency time. 
+	 *
+	 * NOTE: For now if the device is on the 'real time' arbitration
+	 * ring we dont set the latency timer.  
+	 *
+	 * WAR: SGI's IOC3 and RAD devices target abort if you write a 
+	 * single byte into their config space.  So don't set the Latency
+	 * Timer for these devices
+	 */
+
+	lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1);
+
+	if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) &&
+	    !((vendor == IOC3_VENDOR_ID_NUM) && 
+	      (
+#ifdef PIC_LATER
+	       (device == IOC3_DEVICE_ID_NUM) ||
+	       (device == LINC_DEVICE_ID_NUM) ||
+#endif
+	       (device == 0x5 /* RAD_DEV */)))) {
+	     unsigned	min_gnt;
+	     unsigned	min_gnt_mult;
+	    
+	    /* 'min_gnt' indicates how long of a burst period a device
+	     * needs in increments of 250ns.  But latency timer is in
+	     * PCI clock cycles, so a conversion is needed.
+	     */
+	    min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1);
+
+	    if (IS_133MHZ(pcibr_soft))
+		min_gnt_mult = 32;	/* 250ns @ 133MHz in clocks */
+	    else if (IS_100MHZ(pcibr_soft))
+		min_gnt_mult = 24;	/* 250ns @ 100MHz in clocks */
+	    else if (IS_66MHZ(pcibr_soft))
+		min_gnt_mult = 16;	/* 250ns @ 66MHz, in clocks */
+	    else
+		min_gnt_mult = 8;	/* 250ns @ 33MHz, in clocks */
+
+	    if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256))
+		lt_time = (min_gnt * min_gnt_mult);
+	    else
+		lt_time = 4 * min_gnt_mult;	  /* 1 micro second */
+
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time);
+
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: set Latency Timer for slot=%d, "
+		    "func=%d, to 0x%x\n", 
+		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time));
+	}
+
+	/* Get the PCI-X capability if running in PCI-X mode.  If the func
+	 * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE
+	 * pcibr_info struct so the device driver for that function is not
+	 * called.
+	 */
+	if (IS_PCIX(pcibr_soft)) {
+	    if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) {
+		printk(KERN_WARNING
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		        "%v: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", pcibr_vhdl, slot, func);
+#else
+		        "0x%lx: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", (unsigned long)pcibr_vhdl, slot, func);
+#endif
+		pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE,
+		               PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE);
+		continue;
+	    }
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: PCI-X capability at 0x%x for "
+		    "slot=%d, func=%d\n", 
+		    pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func));
+	} else {
+	    pcix_cap = NULL;
 	}
-#if DEBUG && ATTACH_DEBUG
-	printk(KERN_NOTICE   
-		"%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x",
-		pcibr_soft->bs_name, slot, func, vendor, device);
-#endif	
 
 	pcibr_info = pcibr_device_info_new
 	    (pcibr_soft, slot, rfunc, vendor, device);
+
+	/* Keep a running total of the number of PIC-X functions on the bus
+         * and the number of max outstanding split trasnactions that they
+	 * have requested.  NOTE: "pcix_cap != NULL" implies IS_PCIX()
+	 */
+	pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap;
+	if (pcibr_info->f_pcix_cap) {
+	    int max_out;      /* max outstanding splittrans from status reg */
+
+	    pcibr_soft->bs_pcix_num_funcs++;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);
 	if (func == 0)
 	    slotp->slot_conn = conn_vhdl;
 
-#ifdef SN1_LITTLE_ENDIAN
-	cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4];
-#else
-	cmd_reg = cfgw[PCI_CFG_COMMAND / 4];
-#endif
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
 	
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
+	for (win = 0; win < nbars; ++win) {
 	    iopaddr_t               base, mask, code;
 	    size_t                  size;
 
@@ -706,11 +949,7 @@
 	     * this could be pushed up into pciio, when we
 	     * start supporting more PCI providers.
 	     */
-#ifdef SN1_LITTLE_ENDIAN
-	    base = wptr[((win*4)^4)/4];
-#else
-	    base = wptr[win];
-#endif
+	    base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4);
 
 	    if (base & PCI_BA_IO_SPACE) {
 		/* BASE is in I/O space. */
@@ -736,11 +975,7 @@
 		} else if (base & 0xC0000000) {
 		    base = 0;	/* outside permissable range */
 		} else if ((code == PCI_BA_MEM_64BIT) &&
-#ifdef SN1_LITTLE_ENDIAN
-			   (wptr[(((win + 1)*4)^4)/4] != 0)) {
-#else 
-			   (wptr[win + 1] != 0)) {
-#endif /* LITTLE_ENDIAN */
+			   (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) {
 		    base = 0;	/* outside permissable range */
 		}
 	    }
@@ -748,13 +983,8 @@
 	    if (base != 0) {	/* estimate size */
 		size = base & -base;
 	    } else {		/* calculate size */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = ~0;	/* turn on all bits */
-		size = wptr[((win*4)^4)/4];	/* get stored bits */
-#else 
-		wptr[win] = ~0;	/* turn on all bits */
-		size = wptr[win];	/* get stored bits */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0);    /* write 1's */
+		size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */
 		size &= mask;	/* keep addr */
 		size &= -size;	/* keep lsbit */
 		if (size == 0)
@@ -765,28 +995,6 @@
 	    pcibr_info->f_window[win].w_base = base;
 	    pcibr_info->f_window[win].w_size = size;
 
-	    /*
-	     * If this window already has PCI space
-	     * allocated for it, "subtract" that space from
-	     * our running freeblocks. Don't worry about
-	     * overlaps in existing allocated windows; we
-	     * may be overstating their sizes anyway.
-	     */
-
-	    if (base && size) {
-		if (space == PCIIO_SPACE_IO) {
-		    pcibr_freeblock_sub(&pci_io_fb,
-					&pci_io_fl,
-					base, size);
-		} else {
-		    pcibr_freeblock_sub(&pci_lo_fb,
-					&pci_lo_fl,
-					base, size);
-		    pcibr_freeblock_sub(&pci_hi_fb,
-					&pci_hi_fl,
-					base, size);
-		}	
-	    }
 #if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM)
 	    /*
 	     * IOC3 BASE_ADDR* BUG WORKAROUND
@@ -825,21 +1033,55 @@
 #endif
 	    if (code == PCI_BA_MEM_64BIT) {
 		win++;		/* skip upper half */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = 0;	/* which must be zero */
-#else 
-		wptr[win] = 0;	/* which must be zero */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0);  /* must be zero */
 	    }
 	}				/* next win */
     }				/* next func */
 
-    /* Store back the values for allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_STORE();
     return(0);
 }					
 
 /*
+ * pcibr_find_capability
+ *	Walk the list of capabilities (if it exists) looking for
+ *	the requested capability.  Return a cfg_p pointer to the
+ *	capability if found, else return NULL
+ */
+cfg_p
+pcibr_find_capability(cfg_p	cfgw,
+		      unsigned	capability)
+{
+    unsigned		cap_nxt;
+    unsigned		cap_id;
+    int			defend_against_circular_linkedlist = 0;
+
+    /* Check to see if there is a capabilities pointer in the cfg header */
+    if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) {
+	return (NULL);
+    }
+
+    /*
+     * Read up the capabilities head pointer from the configuration header.
+     * Capabilities are stored as a linked list in the lower 48 dwords of
+     * config space and are dword aligned. (Note: spec states the least two
+     * significant bits of the next pointer must be ignored,  so we mask
+     * with 0xfc).
+     */
+    cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc);
+
+    while (cap_nxt && (defend_against_circular_linkedlist <= 48)) {
+	cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1);
+	if (cap_id == capability) {
+	    return ((cfg_p)((char *)cfgw + cap_nxt));
+	}
+	cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc);
+	defend_against_circular_linkedlist++;
+    }
+
+    return (NULL);
+}
+
+/*
  * pcibr_slot_info_free
  *	Remove all the PCI infrastructural information associated
  * 	with a particular PCI device.
@@ -854,7 +1096,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
@@ -868,6 +1113,109 @@
     return(0);
 }
 
+/*
+ * pcibr_slot_pcix_rbar_init
+ *	Allocate RBARs to the PCI-X functions on a given device
+ */
+int
+pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,
+			    pciio_slot_t slot)
+{
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
+    char		 tmp_str[256];
+    int		       	 nfunc;
+    int			 func;
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
+
+    if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1)
+	return(EINVAL);
+
+    if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos))
+	return(EINVAL);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"pcibr_slot_pcix_rbar_init for slot %d\n", 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot)));
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"\tslot/func\trequested\tgiven\tinuse\tavail\n"));
+
+    for (func = 0; func < nfunc; ++func) {
+	cap_pcix_type0_t	*pcix_cap_p;
+	cap_pcix_stat_reg_t	*pcix_statreg_p;
+	cap_pcix_cmd_reg_t	*pcix_cmdreg_p;
+	int 			 num_rbar;
+
+	if (!(pcibr_info = pcibr_infoh[func]))
+	    continue;
+
+	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
+	    continue;
+
+	if (!(pcix_cap_p = pcibr_info->f_pcix_cap))
+	    continue;
+
+	pcix_statreg_p = &pcix_cap_p->pcix_type0_status;
+	pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command;
+
+	/* If there are enough RBARs to satify the number of "max outstanding 
+	 * transactions" each function requested (bs_pcix_rbar_percent_allowed
+	 * is 100%), then give each function what it requested, otherwise give 
+	 * the functions a "percentage of what they requested".
+	 */
+	if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) {
+	    pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+	    pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	} else {
+	    int index;	    /* index into max_splittrans_to_numbuf table */
+	    int max_out;    /* max outstanding transactions given to func */
+
+	    /* Calculate the percentage of RBARs this function can have.
+	     * NOTE: Every function gets at least 1 RBAR (thus the "+1").
+	     * bs_pcix_rbar_percent_allowed is the percentage of what was
+	     * requested less this 1 RBAR that all functions automatically 
+	     * gets
+	     */
+	    max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split]
+			* pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1;
+
+	    /* round down the newly caclulated max_out to a valid number in
+	     * max_splittrans_to_numbuf[]
+	     */
+	    for (index = 0; index < MAX_SPLIT_TABLE-1; index++)
+		if (max_splittrans_to_numbuf[index + 1] > max_out)
+		    break;
+
+	    pcix_cmdreg_p->max_split = index;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+            pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	}
+        /*
+         * The kernel only allows functions to have so many variable args,
+         * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf
+         * arguments fails so sprintf() it into a temporary string.
+         */
+	if (pcibr_debug_mask & PCIBR_DEBUG_RBAR) {
+            sprintf(tmp_str,"\t  %d/%d   \t    %d    \t  %d  \t  %d  \t  %d\n",
+	            PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func,
+	            max_splittrans_to_numbuf[pcix_statreg_p->max_out_split],
+	            max_splittrans_to_numbuf[pcix_cmdreg_p->max_split],
+	            pcibr_soft->bs_pcix_rbar_inuse, 
+		    pcibr_soft->bs_pcix_rbar_avail);
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, 
+		        "%s", tmp_str));
+	}
+    }
+    return(0);
+}
+
 int as_debug = 0;
 /*
  * pcibr_slot_addr_space_init
@@ -878,34 +1226,27 @@
 pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,
 			   pciio_slot_t	slot)
 {
-    pcibr_soft_t	pcibr_soft;
-    pcibr_info_h	pcibr_infoh;
-    pcibr_info_t	pcibr_info;
+    pcibr_soft_t	 pcibr_soft;
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    iopaddr_t		pci_io_fb, pci_io_fl;
-    iopaddr_t		pci_lo_fb, pci_lo_fl;
-    iopaddr_t		pci_hi_fb, pci_hi_fl;
-    size_t              align;
-    iopaddr_t           mask;
-    int		    	nbars;
-    int		       	nfunc;
-    int			func;
-    int			win;
+    size_t               align_slot;
+    iopaddr_t            mask;
+    int		       	 nbars;
+    int		       	 nfunc;
+    int			 func;
+    int			 win;
+    int                  rc = 0;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
-
-    /* Get the current values for the allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    if (as_debug)
-#ifdef LATER
-    PCI_ADDR_SPACE_LIMITS_PRINT();
-#endif
+    bridge = pcibr_soft->bs_base;
 
     /* allocate address space,
      * for windows that have not been
@@ -934,10 +1275,7 @@
      * the entire "lo" area is only a
      * megabyte, total ...
      */
-    align = (slot < 2) ? 0x200000 : 0x100000;
-    mask = -align;
-    pci_io_fb = (pci_io_fb + align - 1) & mask;
-    pci_hi_fb = (pci_hi_fb + align - 1) & mask;
+    align_slot = (slot < 2) ? 0x200000 : 0x100000;
 
     for (func = 0; func < nfunc; ++func) {
 	cfg_p                   cfgw;
@@ -945,7 +1283,9 @@
 	pciio_space_t           space;
 	iopaddr_t               base;
 	size_t                  size;
-	cfg_p                   pci_cfg_cmd_reg_p;
+#ifdef PCI_LATER
+	char			tmp_str[256];
+#endif
 	unsigned                pci_cfg_cmd_reg;
 	unsigned                pci_cfg_cmd_reg_add = 0;
 
@@ -957,13 +1297,15 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 	
-	cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+        cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	nbars = PCI_CFG_BASE_ADDRS;
+	if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0)
+	    nbars = 2;
+	else
+	    nbars = PCI_CFG_BASE_ADDRS;
 
 	for (win = 0; win < nbars; ++win) {
-
 	    space = pcibr_info->f_window[win].w_space;
 	    base = pcibr_info->f_window[win].w_base;
 	    size = pcibr_info->f_window[win].w_size;
@@ -972,77 +1314,93 @@
 		continue;
 
 	    if (base >= size) {
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n",
-			slot, func, win, space, base, base + size - 1);
-#endif
+		/*
+         	 * The kernel only allows functions to have so many variable
+                 * args attempting to call PCIBR_DEBUG_ALWAYS() with more than
+         	 * 5 printf arguments fails so sprintf() it into a temporary 
+		 * string (tmp_str).
+         	 */
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+		if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+		    sprintf(tmp_str, "pcibr_slot_addr_space_init: slot=%d, "
+			"func=%d win %d is in %r [0x%x..0x%x], allocated by "
+			"prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+			func, win, space, space_desc, base, base + size - 1);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+		}
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 		continue;		/* already allocated */
 	    }
-	    align = size;		/* ie. 0x00001000 */
-	    if (align < _PAGESZ)
-		align = _PAGESZ;	/* ie. 0x00004000 */
-	    mask = -align;		/* ie. 0xFFFFC000 */
 
 	    switch (space) {
 	    case PCIIO_SPACE_IO:
-		base = (pci_io_fb + align - 1) & mask;
-		if ((base + size) > pci_io_fl) {
-		    base = 0;
-		    break;
-		}
-		pci_io_fb = base + size;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_window[win],
+                                            PCIIO_SPACE_IO,
+                                            0, size, align_slot);
+                if (!base)
+                    rc = ENOSPC;
 		break;
 		
 	    case PCIIO_SPACE_MEM:
-#ifdef SN1_LITTLE_ENDIAN
-		if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) ==
-#else
-		if ((wptr[win] & PCI_BA_MEM_LOCATION) ==
-#endif  /* LITTLE_ENDIAN */
-		    PCI_BA_MEM_1MEG) {
+		if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) &
+		     PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) {
+                    int align = size;           /* ie. 0x00001000 */
+                    
+                    if (align < _PAGESZ)
+                        align = _PAGESZ;        /* ie. 0x00004000 */
+ 
 		    /* allocate from 20-bit PCI space */
-		    base = (pci_lo_fb + align - 1) & mask;
-		    if ((base + size) > pci_lo_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_lo_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM,
+                                                0, size, align);
+                    if (!base)
+                        rc = ENOSPC;
 		} else {
 		    /* allocate from 32-bit or 64-bit PCI space */
-		    base = (pci_hi_fb + align - 1) & mask;
-		    if ((base + size) > pci_hi_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_hi_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM32,
+                                                0, size, align_slot);
+		    if (!base) 
+			rc = ENOSPC;
 		}
 		break;
 		
 	    default:
 		base = 0;
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d window %d had bad space code %d\n",
-			slot, win, space);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+			    "pcibr_slot_addr_space_init: slot=%d, window %d "
+			    "had bad space code %d\n", 
+			    PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space));
 	    }
 	    pcibr_info->f_window[win].w_base = base;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[((win*4)^4)/4] = base;
-#if DEBUG && PCI_DEBUG
-		printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base);
-#endif
-#else
-	    wptr[win] = base;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base);
 
-#if DEBUG && PCI_DEBUG
-	    if (base >= size)
-		printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n",
-			slot, func, win, space, base, base + size - 1);
-	    else
-		printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n",
-			slot, func, win, size, space);
-#endif
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+	    if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+                if (base >= size) {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d is in %r[0x%x..0x%x], "
+				    "allocated by pcibr\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, space, space_desc, base, 
+				    base + size - 1);
+		     PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				 "%s",tmp_str));
+	        }
+		else {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d, unable to alloc 0x%x in %r\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, size, space, space_desc);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+	        }
+	    }
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 	}				/* next base */
 
 	/*
@@ -1055,34 +1413,23 @@
 	    (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) {
 
 	    wptr = cfgw + PCI_EXPANSION_ROM / 4;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[1] = 0xFFFFF000;
-	    mask = wptr[1];
-#else
-	    *wptr = 0xFFFFF000;
-	    mask = *wptr;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000);
+	    mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4);
 	    if (mask & 0xFFFFF000) {
 		size = mask & -mask;
-		align = size;
-		if (align < _PAGESZ)
-		    align = _PAGESZ;
-		mask = -align;
-		base = (pci_hi_fb + align - 1) & mask;
-		if ((base + size) > pci_hi_fl)
-		    base = size = 0;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_rwindow,
+                                            PCIIO_SPACE_MEM32, 
+                                            0, size, align_slot);
+		if (!base)
+		    rc = ENOSPC;
 		else {
-		    pci_hi_fb = base + size;
-#ifdef SN1_LITTLE_ENDIAN
-		    wptr[1] = base;
-#else
-		    *wptr = base;
-#endif  /* LITTLE_ENDIAN */
-#if DEBUG && PCI_DEBUG
-		    printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n",
-			    pcibr_soft->bs_name, slot,
-			    base, base + size - 1);
-#endif
+		    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+				"pcibr_slot_addr_space_init: slot=%d, func=%d, "
+				"ROM in [0x%X..0x%X], allocated by pcibr\n",
+				PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				func, base, base + size - 1));
 		}
 	    }
 	}
@@ -1116,30 +1463,25 @@
 
 	pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER;
 
-	pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4;
-	pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p;
+	pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+
 #if PCI_FBBE	/* XXX- check here to see if dev can do fast-back-to-back */
 	if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP))
 	    fast_back_to_back_enable = 0;
 #endif
 	pci_cfg_cmd_reg &= 0xFFFF;
 	if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg)
-	    *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add;
-	
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, 
+				pci_cfg_cmd_reg | pci_cfg_cmd_reg_add);
     }				/* next func */
-
-    /* Now that we have allocated new chunks of PCI address spaces to this
-     * card we need to update the bookkeeping values which indicate
-     * the current PCI address space allocations.
-     */
-    PCI_ADDR_SPACE_LIMITS_STORE();
-    return(0);
+    return(rc);
 }
 
 /*
  * pcibr_slot_device_init
  * 	Setup the device register in the bridge for this PCI slot.
  */
+
 int
 pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,
 		       pciio_slot_t slot)
@@ -1150,7 +1492,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
@@ -1161,21 +1506,28 @@
      */
     devreg = bridge->b_device[slot].reg;
     devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS;
-    devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
-#ifdef LITTLE_ENDIAN
-    devreg |= BRIDGE_DEV_DEV_SWAP;
-#endif
+
+    /*
+     * PIC WAR. PV# 855271
+     * Don't enable virtual channels in the PIC by default.
+     * Can cause problems with 32-bit devices. (The bit is only intended
+     * for 64-bit devices).  We set the bit in pcibr_try_set_device()
+     * if we're 64-bit and requesting virtual channels.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV855271, pcibr_soft))
+	devreg |= BRIDGE_DEV_COH;
+    else
+	devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
     pcibr_soft->bs_slot[slot].bss_device = devreg;
     bridge->b_device[slot].reg = devreg;
 
-#if DEBUG && PCI_DEBUG
-	printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg);
-#endif
-
-#if DEBUG && PCI_DEBUG
-    printk("pcibr: PCI space allocation done.\n");
+#ifdef PIC_LATER
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl,
+		"pcibr_slot_device_init: Device(%d): %R\n",
+		slot, devreg, device_bits));
+#else
+    printk("pcibr_slot_device_init: Device(%d) 0x%x\n", slot, devreg);
 #endif
-
     return(0);
 }
 
@@ -1194,7 +1546,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     slotp = &pcibr_soft->bs_slot[slot];
@@ -1259,17 +1614,25 @@
     pcibr_info_t	pcibr_info;
     async_attach_t	aa = NULL;
     int			func;
-    devfs_handle_t	xconn_vhdl,conn_vhdl;
+    devfs_handle_t	xconn_vhdl, conn_vhdl;
+#ifdef PIC_LATER
+    devfs_handle_t	scsi_vhdl;
+#endif
     int			nfunc;
     int                 error_func;
     int                 error_slot = 0;
     int                 error = ENODEV;
+#ifdef PIC_LATER
+    int                 hwg_err;
+#endif
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host) {
         return(EPERM);
@@ -1303,6 +1666,40 @@
 
 	error_func = pciio_device_attach(conn_vhdl, drv_flags);
 
+#ifdef PIC_LATER
+        /*
+         * Try to assign well-known SCSI controller numbers for hot-plug
+         * insert
+         */
+        if (drv_flags) {
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/0",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/1",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+        }
+#endif /* PIC_LATER */
+
         pcibr_info->f_att_det_error = error_func;
 
 	if (error_func)
@@ -1313,9 +1710,12 @@
     }				/* next func */
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 	    pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;
+	}
     } else {
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
     }
         
@@ -1344,16 +1744,15 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host)
         return(EPERM);
 
-    /* Make sure that we do not detach a system critical function vertex */
-    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
-        return(EPERM);
-
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
 
@@ -1367,6 +1766,14 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 
+	if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) {
+	    int max_out;
+
+	    pcibr_soft->bs_pcix_num_funcs--;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pcibr_info->f_vertex;
 
 	error_func = pciio_device_detach(conn_vhdl, drv_flags);
@@ -1380,22 +1787,22 @@
 
     }				/* next func */
 
-    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
             pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT;
+	}
     } else {
         if (conn_vhdl != GRAPH_VERTEX_NONE) 
             pcibr_device_unregister(conn_vhdl);
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
     }
         
     return(error);
 }
 
-#ifdef LATER
-
 /*
  * pcibr_slot_attach
  *	This is a place holder routine to keep track of all the
@@ -1411,81 +1818,16 @@
                   int         *sub_errorp)
 {
     pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+#ifdef PIC_LATER
     timespec_t    ts;
-    int		  error;
-
-    if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) { 
-        /* Power-up the slot */
-        error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_L1_ERR);
-        } else {
-            pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK;
-            pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP;
-        }
-
-#ifdef LATER
-        /*
-         * Allow cards like the Alteon Gigabit Ethernet Adapter to complete
-         * on-card initialization following the slot reset
-         */
-         ts.tv_sec = 0;                      /* 0 secs */
-         ts.tv_nsec = 500 * (1000 * 1000);   /* 500 msecs */
-         nano_delay(&ts);
-#else
 #endif
-#if 0
-        /* Reset the slot */
-        error = pcibr_slot_reset(pcibr_vhdl, slot)
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RESET_ERR);
-        }
-#endif
-
-        /* Find out what is out there */
-        error = pcibr_slot_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_INFO_INIT_ERR);
-        }
-
-        /* Set up the address space for this slot in the PCI land */
-        error = pcibr_slot_addr_space_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_ADDR_INIT_ERR);
-        }
-
-        /* Setup the device register */
-        error = pcibr_slot_device_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_DEV_INIT_ERR);
-        }
-
-        /* Setup host/guest relations */
-        error = pcibr_slot_guest_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_GUEST_INIT_ERR);
-        }
-
-        /* Initial RRB management */
-        error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RRB_ALLOC_ERR);
-        }
+    int		  error;
 
+    /* Do not allow a multi-function card to be hot-plug inserted */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        if (sub_errorp)
+            *sub_errorp = EPERM;
+        return(PCI_MULTI_FUNC_ERR);
     }
 
     /* Call the device attach */
@@ -1501,7 +1843,6 @@
 
     return(0);
 }
-#endif	/* LATER */
 
 /*
  * pcibr_slot_detach
@@ -1511,13 +1852,42 @@
 int
 pcibr_slot_detach(devfs_handle_t pcibr_vhdl,
 		  pciio_slot_t slot,
-		  int          drv_flags)
+		  int          drv_flags,
+		  char        *l1_msg,
+                  int         *sub_errorp)
 {
+    pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     int		  error;
     
+    /* Make sure that we do not detach a system critical function vertex */
+    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
+        return(PCI_IS_SYS_CRITICAL);
+
     /* Call the device detach function */
     error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));
-    return (error);
+    if (error) {
+        if (sub_errorp)
+            *sub_errorp = error;       
+        return(PCI_SLOT_DRV_DETACH_ERR);
+    }
+
+    /* Recalculate the RBARs for all the devices on the bus since we've
+     * just freed some up and some of the devices could use them.
+     */
+    if (IS_PCIX(pcibr_soft)) {
+	int tmp_slot;
+
+	pcibr_soft->bs_pcix_rbar_inuse = 0;
+	pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
+	pcibr_soft->bs_pcix_rbar_percent_allowed = 
+					pcibr_pcix_rbars_calc(pcibr_soft);
+
+	for (tmp_slot = pcibr_soft->bs_min_slot;
+			tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot)
+            (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot);
+    }
+
+    return (0);
 
 }
 
@@ -1540,11 +1910,14 @@
     devfs_handle_t        conn_vhdl = GRAPH_VERTEX_NONE;
     int                 nfunc;
     int                 func;
-    boolean_t		is_sys_critical_vertex(devfs_handle_t);
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-        return(0);
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
@@ -1574,57 +1947,112 @@
 }
 
 /*
- * pcibr_probe_slot: read a config space word
- * while trapping any errors; reutrn zero if
+ * pcibr_probe_slot_pic: read a config space word
+ * while trapping any errors; return zero if
  * all went OK, or nonzero if there was an error.
  * The value read, if any, is passed back
  * through the valp parameter.
  */
-int
-pcibr_probe_slot(bridge_t *bridge,
-		 cfg_p cfg,
-		 unsigned *valp)
+static int
+pcibr_probe_slot_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
 {
-    int                     rv;
-    bridgereg_t             old_enable, new_enable;
-    int badaddr_val(volatile void *, int, volatile void *);
-
-    old_enable = bridge->b_int_enable;
-    new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+	int rv;
+	picreg_t p_old_enable = (picreg_t)0, p_new_enable;
+	extern int badaddr_val(volatile void *, int, volatile void *);
+
+	p_old_enable = bridge->p_int_enable_64;
+	p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT);
+	bridge->p_int_enable_64 = p_new_enable;
+
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT))
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+
+	if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) {
+		bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR);
+		(void) bridge->b_wid_tflush;	/* flushbus */
+	}
+	rv = badaddr_val((void *) cfg, 4, valp);
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) {
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+		rv = 1;         /* unoccupied slot */
+	}
+	bridge->p_int_enable_64 = p_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	return(rv);
+}
 
-    bridge->b_int_enable = new_enable;
+/*
+ * pcibr_probe_slot_non_pic: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot_non_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
+{
+	int                     rv;
+	bridgereg_t             b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0;
+	extern int              badaddr_val(volatile void *, int, volatile void *);
+
+        b_old_enable = bridge->b_int_enable;
+        b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+        bridge->b_int_enable = b_new_enable;
 
 	/*
 	 * The xbridge doesn't clear b_err_int_view unless
 	 * multi-err is cleared...
 	 */
-	if (is_xbridge(bridge))
-	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
+	if (is_xbridge(bridge)) {
+	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT)
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
-	    }
-
-    if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
-	bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
-	(void) bridge->b_wid_tflush;	/* flushbus */
-    }
-    rv = badaddr_val((void *) cfg, 4, valp);
+	}
 
+        if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
+	    bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
+	    (void) bridge->b_wid_tflush;	/* flushbus */
+        }
+	rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp);
 	/*
 	 * The xbridge doesn't set master timeout in b_int_status
 	 * here.  Fortunately it's in error_interrupt_view.
 	 */
-	if (is_xbridge(bridge))
+	if (is_xbridge(bridge)) {
 	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
 		rv = 1;		/* unoccupied slot */
 	    }
+	}
+        bridge->b_int_enable = b_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+
+    	return(rv);
+}
 
-    bridge->b_int_enable = old_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 
-    return rv;
+/*
+ * pcibr_probe_slot: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot(bridge_t *bridge,
+		 cfg_p cfg,
+		 unsigned *valp)
+{
+    if ( is_pic(bridge) )
+	return(pcibr_probe_slot_pic(bridge, cfg, valp));
+    else
+	return(pcibr_probe_slot_non_pic(bridge, cfg, valp));
 }
 
+
 void
 pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
 {
@@ -1632,10 +2060,13 @@
     pcibr_info_t	pcibr_info;
     pciio_function_t	func;
     pcibr_soft_slot_t	slotp = &pcibr_soft->bs_slot[slot];
+    bridge_t           *bridge = pcibr_soft->bs_base; 
+    cfg_p               cfgw;
     int			nfunc = slotp->bss_ninfo;
     int                 bar;
     int                 devio_index;
     int                 s;
+    unsigned            cmd_reg;
 
 
     for (func = 0; func < nfunc; func++) {
@@ -1646,10 +2077,19 @@
 
         s = pcibr_lock(pcibr_soft);
 
+        /* Disable memory and I/O BARs */
+	cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+	cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE);
+	do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg);
+
         for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) {
             if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE)
                 continue;
 
+            /* Free the PCI bus space */
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_window[bar]);
+
             /* Get index of the DevIO(x) register used to access this BAR */
             devio_index = pcibr_info->f_window[bar].w_devio_index;
 
@@ -1664,6 +2104,11 @@
             }
         }
 
+        /* Free the Expansion ROM PCI bus space */
+	if(pcibr_info->f_rbase && pcibr_info->f_rsize) {
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_rwindow);
+        }
+
         pcibr_unlock(pcibr_soft, s);
 
 	slotp->bss_infos[func] = 0;
@@ -1690,3 +2135,68 @@
     slotp->bss_cmd_shadow = 0;
 
 }
+
+
+iopaddr_t
+pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p,
+                     pciio_space_t space, int start, int size, int align)
+{
+    pciio_win_map_t win_map_p;
+
+    switch (space) {
+
+        case PCIIO_SPACE_IO:
+            win_map_p = &pcibr_soft->bs_io_win_map;
+            break;
+
+        case PCIIO_SPACE_MEM:
+            win_map_p = &pcibr_soft->bs_swin_map;
+            break;
+
+        case PCIIO_SPACE_MEM32:
+            win_map_p = &pcibr_soft->bs_mem_win_map;
+            break;
+
+        default:
+            return 0;
+
+    }
+    return pciio_device_win_alloc(win_map_p,
+				  win_info_p
+				  ? &win_info_p->w_win_alloc
+				  : NULL,
+				  start, size, align);
+}
+
+
+void
+pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p)
+{
+	pciio_device_win_free(&win_info_p->w_win_alloc);
+}
+
+/*
+ * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number
+ * associated with that vertex_hdl.  The true mapping happens from the
+ * io_brick_tab[] array defined in ml/SN/iograph.c
+ */
+int
+pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) 
+{
+    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    xwidgetnum_t	widget = pcibr_soft->bs_xid;
+    int			bricktype = pcibr_soft->bs_bricktype;
+    int			bus = pcibr_soft->bs_busnum;
+    
+    /* 
+     * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum
+     * will be 0 or 1.  For [X]BRIDGE there is 1 bus per widget and 
+     * pcibr_soft->bs_busnum will always be zero.  So we add bs_busnum
+     * to what io_brick_map_widget returns to get the bus number.
+     */
+    if ((bus += io_brick_map_widget(bricktype, widget)) > 0) {
+	return bus;
+    } else {
+	return 0;
+    }
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)