3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/module.h>
13 #include <linux/byteorder/swab.h>
14 #include <asm/sn/sgi.h>
15 #include <asm/sn/sn_cpuid.h>
16 #include <asm/sn/addrs.h>
17 #include <asm/sn/arch.h>
18 #include <asm/sn/iograph.h>
19 #include <asm/sn/invent.h>
20 #include <asm/sn/hcl.h>
21 #include <asm/sn/labelcl.h>
22 #include <asm/sn/xtalk/xwidget.h>
23 #include <asm/sn/pci/bridge.h>
24 #include <asm/sn/pci/pciio.h>
25 #include <asm/sn/pci/pcibr.h>
26 #include <asm/sn/pci/pcibr_private.h>
27 #include <asm/sn/pci/pci_defs.h>
28 #include <asm/sn/prio.h>
29 #include <asm/sn/xtalk/xbow.h>
30 #include <asm/sn/ioc3.h>
31 #include <asm/sn/io.h>
32 #include <asm/sn/sn_private.h>
34 extern pcibr_info_t pcibr_info_get(vertex_hdl_t);
36 uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned);
37 uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned);
38 void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t);
39 void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
42 * on sn-ia we need to twiddle the the addresses going out
43 * the pci bus because we use the unswizzled synergy space
44 * (the alternative is to use the swizzled synergy space
45 * and byte swap the data)
47 #define CB(b,r) (((volatile uint8_t *) b)[((r)^4)])
48 #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)])
49 #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)])
51 #define CBP(b,r) (((volatile uint8_t *) b)[(r)])
52 #define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)])
53 #define CWP(b,r) (((volatile uint32_t *) b)[(r)/4])
55 #define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)])
56 #define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)])
57 #define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)])
60 * Return a config space address for given slot / func / offset. Note the
61 * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to
62 * the 32bit word that contains the "offset" byte.
65 pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot,
66 pciio_function_t func, int offset)
72 bridge->b_pci_cfg = ((bus << 16) | (slot << 11));
73 return &bridge->b_type1_cfg.f[func].l[(offset)];
80 return &bridge->b_type0_cfg_dev[slot].f[func].l[offset];
84 * Return config space address for given slot / offset. Note the returned
85 * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the
86 * 32bit word that contains the "offset" byte.
89 pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset)
91 return pcibr_func_config_addr(bridge, 0, slot, 0, offset);
95 * Return config space data for given slot / offset
98 pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset)
102 cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
103 return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned)));
107 * Return config space data for given slot / func / offset
110 pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot,
111 pciio_function_t func, int offset)
115 cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
116 return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned)));
120 * Set config space data for given slot / offset
123 pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot,
124 int offset, unsigned val)
128 cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
129 do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val);
133 * Set config space data for given slot / func / offset
136 pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot,
137 pciio_function_t func, int offset, unsigned val)
141 cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
142 do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val);
145 int pcibr_config_debug = 0;
148 pcibr_config_addr(vertex_hdl_t conn,
151 pcibr_info_t pcibr_info;
152 pciio_bus_t pciio_bus;
153 pciio_slot_t pciio_slot;
154 pciio_function_t pciio_func;
155 pcibr_soft_t pcibr_soft;
157 cfg_p cfgbase = (cfg_p)0;
158 pciio_info_t pciio_info;
160 pciio_info = pciio_info_get(conn);
161 pcibr_info = pcibr_info_get(conn);
164 * Determine the PCI bus/slot/func to generate a config address for.
167 if (pciio_info_type1_get(pciio_info)) {
169 * Conn is a vhdl which uses TYPE 1 addressing explicitly passed
172 pciio_bus = PCI_TYPE1_BUS(reg);
173 pciio_slot = PCI_TYPE1_SLOT(reg);
174 pciio_func = PCI_TYPE1_FUNC(reg);
176 ASSERT(pciio_bus != 0);
179 * Conn is directly connected to the host bus. PCI bus number is
180 * hardcoded to 0 (even though it may have a logical bus number != 0)
181 * and slot/function are derived from the pcibr_info_t associated
186 pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
187 if (pciio_slot == PCIIO_SLOT_NONE)
188 pciio_slot = PCI_TYPE1_SLOT(reg);
190 pciio_func = pcibr_info->f_func;
191 if (pciio_func == PCIIO_FUNC_NONE)
192 pciio_func = PCI_TYPE1_FUNC(reg);
195 pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
197 bridge = pcibr_soft->bs_base;
199 cfgbase = pcibr_func_config_addr(bridge,
200 pciio_bus, pciio_slot, pciio_func, 0);
206 pcibr_config_get(vertex_hdl_t conn,
210 return do_pcibr_config_get(pcibr_config_addr(conn, reg),
211 PCI_TYPE1_REG(reg), size);
215 do_pcibr_config_get(cfg_p cfgbase,
221 value = CWP(cfgbase, reg);
223 value >>= 8 * (reg & 3);
225 value &= (1 << (8 * size)) - 1;
230 pcibr_config_set(vertex_hdl_t conn,
235 do_pcibr_config_set(pcibr_config_addr(conn, reg),
236 PCI_TYPE1_REG(reg), size, value);
240 do_pcibr_config_set(cfg_p cfgbase,
247 CBP(cfgbase, reg) = value;
251 CBP(cfgbase, reg) = value;
252 CBP(cfgbase, reg + 1) = value >> 8;
254 CSP(cfgbase, reg) = value;
258 CBP(cfgbase, reg) = value;
259 CSP(cfgbase, (reg + 1)) = value >> 8;
261 CSP(cfgbase, reg) = value;
262 CBP(cfgbase, reg + 2) = value >> 16;
266 CWP(cfgbase, reg) = value;