patch-2.4.21 linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
Next file: linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c
Previous file: linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c
Back to the patch index
Back to the overall index
- Lines: 387
- Date:
2003-06-13 07:51:31.000000000 -0700
- Orig file:
linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
- Orig date:
2002-08-02 17:39:43.000000000 -0700
diff -urN linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.21/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/byteorder/swab.h>
#include <asm/sn/sgi.h>
#include <asm/sn/sn_cpuid.h>
#include <asm/sn/addrs.h>
@@ -34,14 +35,14 @@
extern pcibr_info_t pcibr_info_get(devfs_handle_t);
uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned);
-uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned);
+uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);
-void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
+void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t);
+static void swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
#ifdef LITTLE_ENDIAN
-#ifdef CONFIG_IA64_SGI_SN1
/*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
* the pci bus because we use the unswizzled synergy space
* (the alternative is to use the swizzled synergy space
* and byte swap the data)
@@ -49,73 +50,218 @@
#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)])
#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)])
#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)])
-#else
-#ifdef CONFIG_IA64_SGI_SN2
-/*
- * On sn-ia sn2 everything is little endian. No swizzling
- * or byte swapping of addresses required.
- */
-#define CB(b,r) (((volatile uint8_t *) b)[(r)])
-#define CS(b,r) (((volatile uint16_t *) b)[(r)/2])
-#define CW(b,r) (((volatile uint32_t *) b)[(r)/4])
-#endif
-#endif
+
+#define CBP(b,r) (((volatile uint8_t *) b)[(r)^3])
+#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)^1])
+#define CWP(b,r) (((volatile uint32_t *) b)[(r)/4])
+
+#define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)])
+#define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)])
+#define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)])
#else
#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3])
#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1])
#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4])
#endif
+/*
+ * Return a config space address for given slot / func / offset. Note the
+ * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to
+ * the 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot,
+ pciio_function_t func, int offset)
+{
+ /*
+ * Type 1 config space
+ */
+ if (bus > 0) {
+ bridge->b_pci_cfg = ((bus << 16) | (slot << 11));
+ return &bridge->b_type1_cfg.f[func].l[(offset)];
+ }
+
+ /*
+ * Type 0 config space
+ */
+ if (is_pic(bridge))
+ slot++;
+ return &bridge->b_type0_cfg_dev[slot].f[func].l[offset];
+}
+
+/*
+ * Return config space address for given slot / offset. Note the returned
+ * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the
+ * 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+ return pcibr_func_config_addr(bridge, 0, slot, 0, offset);
+}
+
+/*
+ * Return config space data for given slot / offset
+ */
+unsigned
+pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+ cfg_p cfg_base;
+
+ cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+ return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Return config space data for given slot / func / offset
+ */
+unsigned
+pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot,
+ pciio_function_t func, int offset)
+{
+ cfg_p cfg_base;
+
+ cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+ return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Set config space data for given slot / offset
+ */
+void
+pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot,
+ int offset, unsigned val)
+{
+ cfg_p cfg_base;
+
+ cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+ do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+/*
+ * Set config space data for given slot / func / offset
+ */
+void
+pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot,
+ pciio_function_t func, int offset, unsigned val)
+{
+ cfg_p cfg_base;
+
+ cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+ do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+int pcibr_config_debug = 0;
cfg_p
pcibr_config_addr(devfs_handle_t conn,
unsigned reg)
{
pcibr_info_t pcibr_info;
+ pciio_bus_t pciio_bus;
pciio_slot_t pciio_slot;
pciio_function_t pciio_func;
pcibr_soft_t pcibr_soft;
bridge_t *bridge;
cfg_p cfgbase = (cfg_p)0;
+ pciio_info_t pciio_info;
+ pciio_info = pciio_info_get(conn);
pcibr_info = pcibr_info_get(conn);
- pciio_slot = pcibr_info->f_slot;
+ /*
+ * Determine the PCI bus/slot/func to generate a config address for.
+ */
+
+ if (pciio_info_type1_get(pciio_info)) {
+ /*
+ * Conn is a vhdl which uses TYPE 1 addressing explicitly passed
+ * in reg.
+ */
+ pciio_bus = PCI_TYPE1_BUS(reg);
+ pciio_slot = PCI_TYPE1_SLOT(reg);
+ pciio_func = PCI_TYPE1_FUNC(reg);
+
+ ASSERT(pciio_bus != 0);
+#if 0
+ } else if (conn != pciio_info_hostdev_get(pciio_info)) {
+ /*
+ * Conn is on a subordinate bus, so get bus/slot/func directly from
+ * its pciio_info_t structure.
+ */
+ pciio_bus = pciio_info->c_bus;
+ pciio_slot = pciio_info->c_slot;
+ pciio_func = pciio_info->c_func;
+ if (pciio_func == PCIIO_FUNC_NONE) {
+ pciio_func = 0;
+ }
+#endif
+ } else {
+ /*
+ * Conn is directly connected to the host bus. PCI bus number is
+ * hardcoded to 0 (even though it may have a logical bus number != 0)
+ * and slot/function are derived from the pcibr_info_t associated
+ * with the device.
+ */
+ pciio_bus = 0;
+
+ pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
if (pciio_slot == PCIIO_SLOT_NONE)
pciio_slot = PCI_TYPE1_SLOT(reg);
pciio_func = pcibr_info->f_func;
if (pciio_func == PCIIO_FUNC_NONE)
pciio_func = PCI_TYPE1_FUNC(reg);
+ }
pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
bridge = pcibr_soft->bs_base;
- cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l;
+ cfgbase = pcibr_func_config_addr(bridge,
+ pciio_bus, pciio_slot, pciio_func, 0);
return cfgbase;
}
+extern unsigned char Is_pic_on_this_nasid[];
uint64_t
pcibr_config_get(devfs_handle_t conn,
unsigned reg,
unsigned size)
{
- return do_pcibr_config_get(pcibr_config_addr(conn, reg),
- PCI_TYPE1_REG(reg), size);
+ if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+ return do_pcibr_config_get(0, pcibr_config_addr(conn, reg),
+ PCI_TYPE1_REG(reg), size);
+ else
+ return do_pcibr_config_get(1, pcibr_config_addr(conn, reg),
+ PCI_TYPE1_REG(reg), size);
}
uint64_t
do_pcibr_config_get(
+ int pic,
cfg_p cfgbase,
unsigned reg,
unsigned size)
{
unsigned value;
- value = CW(cfgbase, reg);
-
+ if ( pic ) {
+ value = CWP(cfgbase, reg);
+ }
+ else {
+ if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) {
+ /*
+ * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped!
+ * Do not swizzle address and byte swap the result.
+ */
+ value = SCW(cfgbase, reg);
+ value = __swab32(value);
+ } else {
+ value = CW(cfgbase, reg);
+ }
+ }
if (reg & 3)
value >>= 8 * (reg & 3);
if (size < 4)
@@ -129,39 +275,103 @@
unsigned size,
uint64_t value)
{
- do_pcibr_config_set(pcibr_config_addr(conn, reg),
+ if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+ do_pcibr_config_set(1, pcibr_config_addr(conn, reg),
+ PCI_TYPE1_REG(reg), size, value);
+ else
+ swap_do_pcibr_config_set(pcibr_config_addr(conn, reg),
PCI_TYPE1_REG(reg), size, value);
}
void
-do_pcibr_config_set(cfg_p cfgbase,
+do_pcibr_config_set(int pic,
+ cfg_p cfgbase,
unsigned reg,
unsigned size,
uint64_t value)
{
+ if ( pic ) {
+ switch (size) {
+ case 1:
+ CBP(cfgbase, reg) = value;
+ break;
+ case 2:
+ if (reg & 1) {
+ CBP(cfgbase, reg) = value;
+ CBP(cfgbase, reg + 1) = value >> 8;
+ } else
+ CSP(cfgbase, reg) = value;
+ break;
+ case 3:
+ if (reg & 1) {
+ CBP(cfgbase, reg) = value;
+ CSP(cfgbase, (reg + 1)) = value >> 8;
+ } else {
+ CSP(cfgbase, reg) = value;
+ CBP(cfgbase, reg + 2) = value >> 16;
+ }
+ break;
+ case 4:
+ CWP(cfgbase, reg) = value;
+ break;
+ }
+ }
+ else {
+ switch (size) {
+ case 1:
+ CB(cfgbase, reg) = value;
+ break;
+ case 2:
+ if (reg & 1) {
+ CB(cfgbase, reg) = value;
+ CB(cfgbase, reg + 1) = value >> 8;
+ } else
+ CS(cfgbase, reg) = value;
+ break;
+ case 3:
+ if (reg & 1) {
+ CB(cfgbase, reg) = value;
+ CS(cfgbase, (reg + 1)) = value >> 8;
+ } else {
+ CS(cfgbase, reg) = value;
+ CB(cfgbase, reg + 2) = value >> 16;
+ }
+ break;
+ case 4:
+ CW(cfgbase, reg) = value;
+ break;
+ }
+ }
+}
+
+void
+swap_do_pcibr_config_set(cfg_p cfgbase,
+ unsigned reg,
+ unsigned size,
+ uint64_t value)
+{
+
+ uint64_t temp_value = 0;
+
switch (size) {
case 1:
- CB(cfgbase, reg) = value;
- break;
+ SCB(cfgbase, reg) = value;
+ break;
case 2:
- if (reg & 1) {
- CB(cfgbase, reg) = value;
- CB(cfgbase, reg + 1) = value >> 8;
- } else
- CS(cfgbase, reg) = value;
- break;
+ temp_value = __swab16(value);
+ if (reg & 1) {
+ SCB(cfgbase, reg) = temp_value;
+ SCB(cfgbase, reg + 1) = temp_value >> 8;
+ } else
+ SCS(cfgbase, reg) = temp_value;
+ break;
case 3:
- if (reg & 1) {
- CB(cfgbase, reg) = value;
- CS(cfgbase, (reg + 1)) = value >> 8;
- } else {
- CS(cfgbase, reg) = value;
- CB(cfgbase, reg + 2) = value >> 16;
- }
- break;
+ BUG();
+ break;
case 4:
- CW(cfgbase, reg) = value;
- break;
+ temp_value = __swab32(value);
+ SCW(cfgbase, reg) = temp_value;
+ break;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)