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

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

diff -urN linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c
@@ -33,259 +33,478 @@
 
 void              do_pcibr_rrb_clear(bridge_t *, int);
 void              do_pcibr_rrb_flush(bridge_t *, int);
-int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t);
+int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t, int);
 int               do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t);
-int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int);
-int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int);
+int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int, int);
+int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int, int);
+void		  do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t);
 
-void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int);
+void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);
 
 int		  pcibr_wrb_flush(devfs_handle_t);
 int               pcibr_rrb_alloc(devfs_handle_t, int *, int *);
 int               pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *);
-int               pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int);
 void              pcibr_rrb_flush(devfs_handle_t);
 int		  pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
 
-/* 
- *    RRB Management
- */
-
-#define LSBIT(word)		((word) &~ ((word)-1))
-
-void
-do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
-{
-    bridgereg_t             status;
-
-    /* bridge_lock must be held;
-     * this RRB must be disabled.
-     */
-
-    /* wait until RRB has no outstanduing XIO packets. */
-    while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
-	;				/* XXX- beats on bridge. bad idea? */
-    }
-
-    /* if the RRB has data, drain it. */
-    if (status & BRIDGE_RRB_VALID(rrb)) {
-	bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
-
-	/* wait until RRB is no longer valid. */
-	while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
-	    ;				/* XXX- beats on bridge. bad idea? */
-	}
-    }
-}
-
-void
-do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
-{
-    reg_p                   rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
-    bridgereg_t             rrbv;
-    int                     shft = 4 * (rrbn >> 1);
-    unsigned                ebit = BRIDGE_RRB_EN << shft;
-
-    rrbv = *rrbp;
-    if (rrbv & ebit)
-	*rrbp = rrbv & ~ebit;
-
-    do_pcibr_rrb_clear(bridge, rrbn);
-
-    if (rrbv & ebit)
-	*rrbp = rrbv;
-}
+void		  pcibr_rrb_debug(char *, pcibr_soft_t);
 
 /*
- *    pcibr_rrb_count_valid: count how many RRBs are
- *      marked valid for the specified PCI slot on this
- *      bridge.
- *
- *      NOTE: The "slot" parameter for all pcibr_rrb
- *      management routines must include the "virtual"
- *      bit; when manageing both the normal and the
- *      virtual channel, separate calls to these
- *      routines must be made. To denote the virtual
- *      channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot
- *      number.
- *
- *      IMPL NOTE: The obvious algorithm is to iterate
- *      through the RRB fields, incrementing a count if
- *      the RRB is valid and matches the slot. However,
- *      it is much simpler to use an algorithm derived
- *      from the "partitioned add" idea. First, XOR in a
- *      pattern such that the fields that match this
- *      slot come up "all ones" and all other fields
- *      have zeros in the mismatching bits. Then AND
- *      together the bits in the field, so we end up
- *      with one bit turned on for each field that
- *      matched. Now we need to count these bits. This
- *      can be done either with a series of shift/add
- *      instructions or by using "tmp % 15"; I expect
- *      that the cascaded shift/add will be faster.
- */
-
+ * RRB Management
+ *
+ * All the do_pcibr_rrb_ routines manipulate the Read Response Buffer (rrb)
+ * registers within the Bridge.	 Two 32 registers (b_rrb_map[2] also known
+ * as the b_even_resp & b_odd_resp registers) are used to allocate the 16
+ * rrbs to devices.  The b_even_resp register represents even num devices,
+ * and b_odd_resp represent odd number devices.	 Each rrb is represented by
+ * 4-bits within a register.
+ *   BRIDGE & XBRIDGE:	1 enable bit, 1 virtual channel bit, 2 device bits
+ *   PIC:		1 enable bit, 2 virtual channel bits, 1 device bit
+ * PIC has 4 devices per bus, and 4 virtual channels (1 normal & 3 virtual)
+ * per device.	BRIDGE & XBRIDGE have 8 devices per bus and 2 virtual
+ * channels (1 normal & 1 virtual) per device.	See the BRIDGE and PIC ASIC
+ * Programmers Reference guides for more information.
+ */ 
+ 
+#define RRB_MASK (0xf)			/* mask a single rrb within reg */
+#define RRB_SIZE (4)			/* sizeof rrb within reg (bits) */
+ 
+#define RRB_ENABLE_BIT(bridge)		(0x8)  /* [BRIDGE | PIC]_RRB_EN */
+#define NUM_PDEV_BITS(bridge)		(is_pic((bridge)) ? 1 : 2)
+#define NUM_VDEV_BITS(bridge)		(is_pic((bridge)) ? 2 : 1)
+#define NUMBER_VCHANNELS(bridge)	(is_pic((bridge)) ? 4 : 2)
+#define SLOT_2_PDEV(bridge, slot)	((slot) >> 1)
+#define SLOT_2_RRB_REG(bridge, slot)	((slot) & 0x1)
+ 
+/* validate that the slot and virtual channel are valid for a given bridge */
+#define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \
+  (is_pic((bridge)) ? \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0))
+ 
+/*  
+ * Count how many RRBs are marked valid for the specified PCI slot
+ * and virtual channel.	 Return the count.
+ */ 
 int
 do_pcibr_rrb_count_valid(bridge_t *bridge,
-			 pciio_slot_t slot)
+			 pciio_slot_t slot,
+			 int vchan)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index, cnt=0;
+
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan);
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+    
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp ^= 0x11111111 * (7 - slot / 2);
-    tmp &= (0xCCCCCCCC & tmp) >> 2;
-    tmp &= (0x22222222 & tmp) >> 1;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_count_avail: count how many RRBs are
- *      available to be allocated for the specified slot.
- *
- *      IMPL NOTE: similar to the above, except we are
- *      just counting how many fields have the valid bit
- *      turned off.
- */
+ 
+ 
+/*  
+ * Count how many RRBs are available to be allocated to the specified
+ * slot.  Return the count.
+ */ 
 int
 do_pcibr_rrb_count_avail(bridge_t *bridge,
 			 pciio_slot_t slot)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit;
+    int rrb_index, cnt=0;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, 0)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan");
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~tmp) >> 3;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_alloc: allocate some additional RRBs
- *      for the specified slot. Returns -1 if there were
- *      insufficient free RRBs to satisfy the request,
- *      or 0 if the request was fulfilled.
- *
- *      Note that if a request can be partially filled,
- *      it will be, even if we return failure.
- *
- *      IMPL NOTE: again we avoid iterating across all
- *      the RRBs; instead, we form up a word containing
- *      one bit for each free RRB, then peel the bits
- *      off from the low end.
- */
+ 
+ 
+/*  
+ * Allocate some additional RRBs for the specified slot and the specified
+ * virtual channel.  Returns -1 if there were insufficient free RRBs to
+ * satisfy the request, or 0 if the request was fulfilled.
+ *
+ * Note that if a request can be partially filled, it will be, even if
+ * we return failure.
+ */ 
 int
 do_pcibr_rrb_alloc(bridge_t *bridge,
 		   pciio_slot_t slot,
+		   int vchan,
 		   int more)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, bit;
+    bridgereg_t reg, tmp = (bridgereg_t)0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit) {
+	    /* clear the rrb and OR in the new rrb into 'reg' */
+	    reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    reg = reg | (rrb_bits << (RRB_SIZE * rrb_index));
+	    more--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    reg = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~reg) >> 3;
-    while (more-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
 	}
-	tmp &= ~bit;
-	reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2)));
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
-    return rv;
+    return (more ? -1 : 0);
 }
-
-/*
- *    do_pcibr_rrb_free: release some of the RRBs that
- *      have been allocated for the specified
- *      slot. Returns zero for success, or negative if
- *      it was unable to free that many RRBs.
- *
- *      IMPL NOTE: We form up a bit for each RRB
- *      allocated to the slot, aligned with the VALID
- *      bitfield this time; then we peel bits off one at
- *      a time, releasing the corresponding RRB.
- */
+ 
+ 
+/*  
+ * Release some of the RRBs that have been allocated for the specified
+ * slot. Returns zero for success, or negative if it was unable to free
+ * that many RRBs.
+ *
+ * Note that if a request can be partially fulfilled, it will be, even
+ * if we return failure.
+ */ 
 int
 do_pcibr_rrb_free(bridge_t *bridge,
 		  pciio_slot_t slot,
+		  int vchan,
 		  int less)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, clr, bit;
-    int                     i;
+    bridgereg_t reg, tmp = (bridgereg_t)0, clr = 0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits) {
+	   /*
+	    * the old do_pcibr_rrb_free() code only clears the enable bit
+	    * but I say we should clear the whole rrb (ie):
+	    *	  reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    * But to be compatable with old code we'll only clear enable.
+	    */
+	    reg = reg & ~(RRB_ENABLE_BIT(bridge) << (RRB_SIZE * rrb_index));
+	    clr = clr | (enable_bit << (RRB_SIZE * rrb_index));
+	    less--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    clr = 0;
-    reg = bridge->b_rrb_map[slot & 1].reg;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+	}
+    }
 
-    /* This needs to be done otherwise the rrb's on the virtual channel
-     * for this slot won't be freed !!
+    /* call do_pcibr_rrb_clear() for all the rrbs we've freed */
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if (clr & (enable_bit << (RRB_SIZE * rrb_index)))
+	    do_pcibr_rrb_clear(bridge, (2 * rrb_index) + evn_odd);
+    }
+    
+    return (less ? -1 : 0);
+}
+ 
+  
+/*  
+ * free all the rrbs (both the normal and virtual channels) for the
+ * specified slot.
+ */ 
+void
+do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft,
+		      bridge_t *bridge,
+		      pciio_slot_t slot)
+{
+    int vchan;
+    int vchan_total = NUMBER_VCHANNELS(bridge);
+    
+    /* pretend we own all 8 rrbs and just ignore the return value */
+    for (vchan = 0; vchan < vchan_total; vchan++) {
+	    (void)do_pcibr_rrb_free(bridge, slot, vchan, 8);
+	    pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+    }
+}
+ 
+ 
+/*
+ * Wait for the the specified rrb to have no outstanding XIO pkts
+ * and for all data to be drained.  Mark the rrb as no longer being 
+ * valid.
+ */
+void
+do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
+{
+    bridgereg_t             status;
+
+    /* bridge_lock must be held;
+     * this RRB must be disabled.
      */
-    tmp = reg & 0xbbbbbbbb;
 
-    tmp ^= (0x11111111 * (7 - slot / 2));
-    tmp &= (0x33333333 & tmp) << 2;
-    tmp &= (0x44444444 & tmp) << 1;
-    while (less-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	/* wait until RRB has no outstanduing XIO packets. */
+	while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+		;				/* XXX- beats on bridge. bad idea? */
+	}
+
+	/* if the RRB has data, drain it. */
+	if (status & BRIDGE_RRB_VALID(rrb)) {
+		bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+
+		/* wait until RRB is no longer valid. */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+			;				/* XXX- beats on bridge. bad idea? */
+		}
+	}
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb));
+
+			/* wait until RRB is no longer valid. */
+			while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	} else { /* io_get_sh_swapper(NASID_GET(bridge)) */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+			/* wait until RRB is no longer valid. */
+			while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	}
+    }
+}
+
+
+/* 
+ * Flush the specified rrb by calling do_pcibr_rrb_clear().  This
+ * routine is just a wrapper to make sure the rrb is disabled 
+ * before calling do_pcibr_rrb_clear().
+ */
+void
+do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
+{
+    reg_p	 rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
+    bridgereg_t	 rrbv;
+    int		 shft = (RRB_SIZE * (rrbn >> 1));
+    unsigned long	 ebit = RRB_ENABLE_BIT(bridge) << shft;
+
+    if ( is_pic(bridge) ) {
+	rrbv = *rrbp;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		rrbv = BRIDGE_REG_GET32((&rrbp));
+	} else {
+		rrbv = *rrbp;
+	}
+    }
+
+    if (rrbv & ebit) {
+    	if ( is_pic(bridge) ) {
+		*rrbp = rrbv & ~ebit;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit));
+		} else {
+			*rrbp = rrbv & ~ebit;
+		}
 	}
-	tmp &= ~bit;
-	reg &= ~bit;
-	clr |= bit;
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
 
-    for (i = 0; i < 8; i++)
-	if (clr & (8 << (4 * i)))
-	    do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1));
+    do_pcibr_rrb_clear(bridge, rrbn);
 
-    return rv;
+    if (rrbv & ebit) {
+	if ( is_pic(bridge) ) {
+		*rrbp = rrbv;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv);
+		} else {
+			*rrbp = rrbv;
+		}
+	}
+    }
 }
 
+
 void
 do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft,
 		       int slot,
+		       int vchan, 
 		       int more_rrbs)
 {
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     got;
 
     for (got = 0; got < more_rrbs; ++got) {
-	if (pcibr_soft->bs_rrb_res[slot & 7] > 0)
-	    pcibr_soft->bs_rrb_res[slot & 7]--;
+	if (pcibr_soft->bs_rrb_res[slot] > 0)
+	    pcibr_soft->bs_rrb_res[slot]--;
 	else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0)
 	    pcibr_soft->bs_rrb_avail[slot & 1]--;
 	else
 	    break;
-	if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0)
+	if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0)
 	    break;
-#if PCIBR_RRB_DEBUG
-	printk("do_pcibr_rrb_autoalloc: add one to slot %d%s\n",
-		slot & 7, slot & 8 ? "v" : "");
-#endif
-	pcibr_soft->bs_rrb_valid[slot]++;
-    }
-#if PCIBR_RRB_DEBUG
-    printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name,
-	    pcibr_soft->bs_rrb_avail[0],
-	    pcibr_soft->bs_rrb_avail[1]);
-    for (slot = 0; slot < 8; ++slot)
-	printk("\t%d+%d+%d",
-		0xFFF & pcibr_soft->bs_rrb_valid[slot],
-		0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-		pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+
+	pcibr_soft->bs_rrb_valid[slot][vchan]++;
+    }
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		"do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs "
+		"to slot %d, vchan %d\n", got, more_rrbs, 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan));
+
+    pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft);
 }
 
+
+/*
+ * Flush all the rrb's assigned to the specified connection point.
+ */
+void
+pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t  pciio_info = pciio_info_get(pconn_vhdl);
+    pcibr_soft_t  pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info);
+    pciio_slot_t  slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
+    bridge_t	 *bridge = pcibr_soft->bs_base;
+
+    bridgereg_t tmp;
+    uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask;
+    int rrb_index;
+    unsigned long s;
+
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | pdev_bits;
+    rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1);
+
+    tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+
+    s = pcibr_lock(pcibr_soft);
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if ((tmp & rrb_mask) == rrb_bits)
+	    do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd);
+	tmp = (tmp >> RRB_SIZE);
+    }
+    pcibr_unlock(pcibr_soft, s);
+}
+
+
 /*
  * Device driver interface to flush the write buffers for a specified
  * device hanging off the bridge.
@@ -294,14 +513,24 @@
 pcibr_wrb_flush(devfs_handle_t pconn_vhdl)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     volatile bridgereg_t   *wrb_flush;
 
     wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg);
-    while (*wrb_flush);
-
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	while (*wrb_flush)
+		;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while (BRIDGE_REG_GET32((wrb_flush)));
+	} else {
+		while (*wrb_flush)
+			;
+	}
+    }
     return(0);
 }
 
@@ -322,7 +551,7 @@
 		int *count_vchan1)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     desired_vchan0;
@@ -335,7 +564,9 @@
     int                     final_vchan1;
     int                     avail_rrbs;
     int                     res_rrbs;
-    unsigned long           s;
+    int			    vchan_total;
+    int			    vchan;
+    unsigned long                s;
     int                     error;
 
     /*
@@ -352,20 +583,21 @@
 
     s = pcibr_lock(pcibr_soft);
 
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
     /* Save the boot-time RRB configuration for this slot */
-    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] < 0) {
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot] =
-                pcibr_soft->bs_rrb_valid[pciio_slot]; 
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] =
-                pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) {
+	for (vchan = 0; vchan < vchan_total; vchan++) 
+	    pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] =
+		    pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
         pcibr_soft->bs_rrb_res_dflt[pciio_slot] =
                 pcibr_soft->bs_rrb_res[pciio_slot];
                   
     }
 
     /* How many RRBs do we own? */
-    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot];
-    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
+    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
     /* How many RRBs do we want? */
     desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0;
@@ -417,14 +649,14 @@
 	/* Commit the allocations: free, then alloc.
 	 */
 	if (delta_vchan0 < 0)
-	    (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0);
 	if (delta_vchan1 < 0)
-	    (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1);
 
 	if (delta_vchan0 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0);
 	if (delta_vchan1 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1);
 
 	/* Return final values to caller.
 	 */
@@ -442,8 +674,8 @@
 	 * number of available RRBs.
 	 */
 
-	pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0;
-	pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1;
 	pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
 	    pcibr_soft->bs_rrb_avail[pciio_slot & 1]
 	    + pcibr_soft->bs_rrb_res[pciio_slot]
@@ -455,34 +687,21 @@
          * Reserve enough RRBs so this slot's RRB configuration can be
          * reset to its boot-time default following a hot-plug shut-down
          */
-        res_rrbs =   (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot]) 
-                   + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot +
-                                                    PCIBR_RRB_SLOT_VIRTUAL] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot +
-                                               PCIBR_RRB_SLOT_VIRTUAL])
-                   + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_res[pciio_slot]);
-
-         if (res_rrbs > 0) {
-             pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
-             pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
-                 pcibr_soft->bs_rrb_avail[pciio_slot & 1]
-                 - res_rrbs;
-         }
- 
-#if PCIBR_RRB_DEBUG
-	printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n",
-		pciio_slot, final_vchan0, final_vchan1,
-		pcibr_soft->bs_rrb_avail[0],
-		pcibr_soft->bs_rrb_avail[1]);
-	for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot)
-	    printk("\t%d+%d+%d",
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot],
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL],
+	res_rrbs = (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
 		    pcibr_soft->bs_rrb_res[pciio_slot]);
-	printk("\n");
-#endif
+	for (vchan = 0; vchan < vchan_total; vchan++) {
+	    res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] -
+			 pcibr_soft->bs_rrb_valid[pciio_slot][vchan]);
+	}
+
+	if (res_rrbs > 0) {
+            pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
+            pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
+                pcibr_soft->bs_rrb_avail[pciio_slot & 1]
+                - res_rrbs;
+        }
+ 
+	pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft);
 
 	error = 0;
     }
@@ -543,22 +762,22 @@
     pciio_info_t            pciio_info;
     pciio_slot_t            pciio_slot;
     pcibr_soft_t            pcibr_soft;
-    unsigned long           s;
+    unsigned long                s;
     int                     error = -1;
 
     if ((pciio_info = pciio_info_get(pconn_vhdl)) &&
 	(pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) &&
-	((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) {
+	((pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) {
 
 	s = pcibr_lock(pcibr_soft);
 
 	if (count_vchan0)
 	    *count_vchan0 =
-		pcibr_soft->bs_rrb_valid[pciio_slot];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
 
 	if (count_vchan1)
 	    *count_vchan1 =
-		pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
 	if (count_reserved)
 	    *count_reserved =
@@ -575,159 +794,6 @@
     return error;
 }
 
-/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities
- * requested for each of the devices.  The evn_odd argument indicates whether
- * allocation is for the odd or even rrbs. The next group of four argument
- * pairs indicate the amount of rrbs to be assigned to each device. The first
- * argument of each pair indicate the total number of rrbs to allocate for that
- * device. The second argument of each pair indicates how many rrb's from the
- * first argument should be assigned to the virtual channel. The total of all
- * of the first arguments should be <= 8. The second argument should be <= the
- * first argument.
- * if even_odd = 0 the devices in order are 0, 2, 4, 6 
- * if even_odd = 1 the devices in order are 1, 3, 5, 7
- * returns 0 if no errors else returns -1
- */
-
-int
-pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd,
-		     int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2,
-		     int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4)
-{
-    devfs_handle_t          pcibr_vhdl;
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t)0;
-    bridge_t               *bridge = NULL;
-
-    uint32_t                rrb_setting = 0;
-    int                     rrb_shift = 7;
-    uint32_t                cur_rrb;
-    int                     dev_rrbs[4];
-    int                     virt[4];
-    int                     i, j;
-    unsigned long           s;
-
-    if (GRAPH_SUCCESS ==
-	hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) {
-	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-	if (pcibr_soft)
-	    bridge = pcibr_soft->bs_base;
-	hwgraph_vertex_unref(pcibr_vhdl);
-    }
-    if (bridge == NULL)
-	bridge = (bridge_t *) xtalk_piotrans_addr
-	    (vhdl, NULL, 0, sizeof(bridge_t), 0);
-
-    even_odd &= 1;
-
-    dev_rrbs[0] = dev_1_rrbs;
-    dev_rrbs[1] = dev_2_rrbs;
-    dev_rrbs[2] = dev_3_rrbs;
-    dev_rrbs[3] = dev_4_rrbs;
-
-    virt[0] = virt1;
-    virt[1] = virt2;
-    virt[2] = virt3;
-    virt[3] = virt4;
-
-    if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) {
-	return -1;
-    }
-    if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) {
-	return -1;
-    }
-    /* walk through rrbs */
-    for (i = 0; i < 4; i++) {
-	if (virt[i]) {
-		for( j = 0; j < virt[i]; j++) {
-			cur_rrb = i | 0xc;
-			cur_rrb = cur_rrb << (rrb_shift * 4);
-			rrb_shift--;
-			rrb_setting = rrb_setting | cur_rrb;
-			dev_rrbs[i] = dev_rrbs[i] - 1;
-		}
-	}
-	for (j = 0; j < dev_rrbs[i]; j++) {
-	    cur_rrb = i | 0x8;
-	    cur_rrb = cur_rrb << (rrb_shift * 4);
-	    rrb_shift--;
-	    rrb_setting = rrb_setting | cur_rrb;
-	}
-    }
-
-    if (pcibr_soft)
-	s = pcibr_lock(pcibr_soft);
-
-    bridge->b_rrb_map[even_odd].reg = rrb_setting;
-
-    if (pcibr_soft) {
-
-	pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd;
-
-	/* since we've "FIXED" the allocations
-	 * for these slots, we probably can dispense
-	 * with tracking avail/res/valid data, but
-	 * keeping it up to date helps debugging.
-	 */
-
-	pcibr_soft->bs_rrb_avail[even_odd] =
-	    8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs);
-
-	pcibr_soft->bs_rrb_res[even_odd + 0] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 2] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 4] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 6] = 0;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4;
-
-	pcibr_unlock(pcibr_soft, s);
-    }
-    return 0;
-}
-
-/*
- *    pcibr_rrb_flush: chase down all the RRBs assigned
- *      to the specified connection point, and flush
- *      them.
- */
-void
-pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
-{
-    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
-    bridge_t               *bridge = pcibr_soft->bs_base;
-    unsigned long           s;
-    reg_p                   rrbp;
-    unsigned                rrbm;
-    int                     i;
-    int                     rrbn;
-    unsigned                sval;
-    unsigned                mask;
-
-    sval = BRIDGE_RRB_EN | (pciio_slot >> 1);
-    mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV;
-    rrbn = pciio_slot & 1;
-    rrbp = &bridge->b_rrb_map[rrbn].reg;
-
-    s = pcibr_lock(pcibr_soft);
-    rrbm = *rrbp;
-    for (i = 0; i < 8; ++i) {
-	if ((rrbm & mask) == sval)
-	    do_pcibr_rrb_flush(bridge, rrbn);
-	rrbm >>= 4;
-	rrbn += 2;
-    }
-    pcibr_unlock(pcibr_soft, s);
-}
-
 /*
  * pcibr_slot_initial_rrb_alloc
  *	Allocate a default number of rrbs for this slot on 
@@ -743,75 +809,82 @@
     pcibr_info_h	 pcibr_infoh;
     pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    int                  c0, c1, r;
+    int 		 vchan_total;
+    int			 vchan;
+    int                  chan[4];
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    /* How may RRBs are on this slot?
-     */
-    c0 = do_pcibr_rrb_count_valid(bridge, slot);
-    c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL);
+    bridge = pcibr_soft->bs_base;
 
-#if PCIBR_RRB_DEBUG
-    printk(
+    /* How many RRBs are on this slot? */
+    vchan_total = NUMBER_VCHANNELS(bridge);
+    for (vchan = 0; vchan < vchan_total; vchan++) 
+        chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan);
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+ 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
+	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n",
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3]));
+    } else {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
 	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n",
-            slot, c0, c1);
-#endif
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1]));
+    }
 
     /* Do we really need any?
      */
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
     pcibr_info = pcibr_infoh[0];
-    if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
-	!pcibr_soft->bs_slot[slot].has_host) {
-	if (c0 > 0)
-	    do_pcibr_rrb_free(bridge, slot, c0);
-	if (c1 > 0)
-	    do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1);
-	pcibr_soft->bs_rrb_valid[slot] = 0x1000;
-	pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000;
-	return(ENODEV);
-    }
 
-    pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1;
-    pcibr_soft->bs_rrb_valid[slot] = c0;
-    pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1;
-
-    pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0);
-    pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1);
+    if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && IS_PIC_SOFT(pcibr_soft) &&
+                        (slot == 2 || slot == 3) &&
+                        (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
+                        !pcibr_soft->bs_slot[slot].has_host) {
+
+        for (vchan = 0; vchan < 2; vchan++) {
+            do_pcibr_rrb_free(bridge, slot, vchan, 8);
+            pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+        }
 
-    r = 3 - (c0 + c1);
+        pcibr_soft->bs_rrb_valid[slot][3] = chan[3];
 
-    if (r > 0) {
-	pcibr_soft->bs_rrb_res[slot] = r;
-	pcibr_soft->bs_rrb_avail[slot & 1] -= r;
+        return(ENODEV);
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("\t%d+%d+%d",
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot],
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    for (vchan = 0; vchan < vchan_total; vchan++)
+        pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan];
 
     return(0);
 }
 
+void
+rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot)
+{
+        int res = pcibr_soft->bs_rrb_res[slot];
+
+        if (res) {
+                 pcibr_soft->bs_rrb_avail[slot & 1] += res;
+                 pcibr_soft->bs_rrb_res[slot] = 0;
+        }
+}
+
 /*
  * pcibr_initial_rrb
  *      Assign an equal total number of RRBs to all candidate slots, 
  *      where the total is the sum of the number of RRBs assigned to
  *      the normal channel, the number of RRBs assigned to the virtual
- *      channel, and the number of RRBs assigned as reserved. 
+ *      channels, and the number of RRBs assigned as reserved. 
  *
- *      A candidate slot is a populated slot on a non-SN1 system or 
- *      any existing (populated or empty) slot on an SN1 system.
+ *      A candidate slot is any existing (populated or empty) slot.
  *      Empty SN1 slots need RRBs to support hot-plug operations.
  */
 
@@ -822,7 +895,9 @@
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t               *bridge = pcibr_soft->bs_base;
     pciio_slot_t            slot;
-    int                     c0, c1;
+    int			    rrb_total;
+    int			    vchan_total;
+    int			    vchan;
     int                     have[2][3];
     int                     res[2];
     int                     eo;
@@ -831,16 +906,21 @@
     have[1][0] = have[1][1] = have[1][2] = 0;
     res[0] = res[1] = 0;
 
-    for (slot = 0; slot < 8; ++slot) {
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
+    for (slot = pcibr_soft->bs_min_slot; 
+			slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
         /* Initial RRB management; give back RRBs in all non-existent slots */
         (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
 
         /* Base calculations only on existing slots */
         if ((slot >= first) && (slot <= last)) {
-            c0 = pcibr_soft->bs_rrb_valid[slot];
-            c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-            if ((c0 + c1) < 3)
-                have[slot & 1][c0 + c1]++;
+	    rrb_total = 0;
+	    for (vchan = 0; vchan < vchan_total; vchan++) 
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+            if (rrb_total < 3)
+                have[slot & 1][rrb_total]++;
         }
     }
 
@@ -867,30 +947,70 @@
     for (slot = first; slot <= last; ++slot) {
         int                     r;
 
-        c0 = pcibr_soft->bs_rrb_valid[slot];
-        c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-        r = res[slot & 1] - (c0 + c1);
+	rrb_total = 0;
+	for (vchan = 0; vchan < vchan_total; vchan++)
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+        r = res[slot & 1] - (rrb_total);
 
         if (r > 0) {
             pcibr_soft->bs_rrb_res[slot] = r;
             pcibr_soft->bs_rrb_avail[slot & 1] -= r;
-            }
+        }
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("%v RRB MANAGEMENT: %d+%d free\n",
-            pcibr_vhdl,
-            pcibr_soft->bs_rrb_avail[0],
-            pcibr_soft->bs_rrb_avail[1]);
-    for (slot = first; slot <= last; ++slot)
-        printk("\tslot %d: %d+%d+%d", slot,
-                0xFFF & pcibr_soft->bs_rrb_valid[slot],
-                0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-                pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft);
 
     return 0;
 
 }
 
+/*
+ * Dump the pcibr_soft_t RRB state variable
+ */
+void
+pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft)
+{
+    pciio_slot_t slot;
+    char tmp_str[256];
+    
+    if (pcibr_debug_mask & PCIBR_DEBUG_RRB) {
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                    "%s: rrbs available, even=%d, odd=%d\n", calling_func,
+                    pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]));
+
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n"));
+        } else {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		        "\tslot\tvchan0\tvchan1\treserved\n"));
+        }
+
+        for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) {
+	    /*
+             * 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 (IS_PIC_SOFT(pcibr_soft)) {
+                sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3],
+                        pcibr_soft->bs_rrb_res[slot]);
+	    } else {
+	        sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+		        pcibr_soft->bs_rrb_res[slot]);
+	    }
+    
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "%s", tmp_str));
+        }
+    }
+}

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