1 /*
2  *
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
5  * for more details.
6  *
7  * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
8  */
9 
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/module.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/sn_cpuid.h>
15 #include <asm/sn/addrs.h>
16 #include <asm/sn/arch.h>
17 #include <asm/sn/iograph.h>
18 #include <asm/sn/invent.h>
19 #include <asm/sn/hcl.h>
20 #include <asm/sn/labelcl.h>
21 #include <asm/sn/xtalk/xwidget.h>
22 #include <asm/sn/pci/bridge.h>
23 #include <asm/sn/pci/pciio.h>
24 #include <asm/sn/pci/pcibr.h>
25 #include <asm/sn/pci/pcibr_private.h>
26 #include <asm/sn/pci/pci_defs.h>
27 #include <asm/sn/prio.h>
28 #include <asm/sn/xtalk/xbow.h>
29 #include <asm/sn/ioc3.h>
30 #include <asm/sn/io.h>
31 #include <asm/sn/sn_private.h>
32 
33 pcibr_hints_t           pcibr_hints_get(vertex_hdl_t, int);
34 void                    pcibr_hints_fix_rrbs(vertex_hdl_t);
35 void                    pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t);
36 void			pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *);
37 void                    pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t);
38 void                    pcibr_hints_handsoff(vertex_hdl_t);
39 void                    pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t);
40 
41 pcibr_hints_t
pcibr_hints_get(vertex_hdl_t xconn_vhdl,int alloc)42 pcibr_hints_get(vertex_hdl_t xconn_vhdl, int alloc)
43 {
44     arbitrary_info_t        ainfo = 0;
45     graph_error_t	    rv;
46     pcibr_hints_t           hint;
47 
48     rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo);
49 
50     if (alloc && (rv != GRAPH_SUCCESS)) {
51 
52 	NEW(hint);
53 	hint->rrb_alloc_funct = NULL;
54 	hint->ph_intr_bits = NULL;
55 	rv = hwgraph_info_add_LBL(xconn_vhdl,
56 				  INFO_LBL_PCIBR_HINTS,
57 				  (arbitrary_info_t) hint);
58 	if (rv != GRAPH_SUCCESS)
59 	    goto abnormal_exit;
60 
61 	rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo);
62 
63 	if (rv != GRAPH_SUCCESS)
64 	    goto abnormal_exit;
65 
66 	if (ainfo != (arbitrary_info_t) hint)
67 	    goto abnormal_exit;
68     }
69     return (pcibr_hints_t) ainfo;
70 
71 abnormal_exit:
72 #ifdef LATER
73     printf("SHOULD NOT BE HERE\n");
74 #endif
75     DEL(hint);
76     return(NULL);
77 
78 }
79 
80 void
pcibr_hints_fix_some_rrbs(vertex_hdl_t xconn_vhdl,unsigned mask)81 pcibr_hints_fix_some_rrbs(vertex_hdl_t xconn_vhdl, unsigned mask)
82 {
83     pcibr_hints_t           hint = pcibr_hints_get(xconn_vhdl, 1);
84 
85     if (hint)
86 	hint->ph_rrb_fixed = mask;
87     else
88         PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
89 		    "pcibr_hints_fix_rrbs: pcibr_hints_get failed\n"));
90 }
91 
92 void
pcibr_hints_fix_rrbs(vertex_hdl_t xconn_vhdl)93 pcibr_hints_fix_rrbs(vertex_hdl_t xconn_vhdl)
94 {
95     pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF);
96 }
97 
98 void
pcibr_hints_dualslot(vertex_hdl_t xconn_vhdl,pciio_slot_t host,pciio_slot_t guest)99 pcibr_hints_dualslot(vertex_hdl_t xconn_vhdl,
100 		     pciio_slot_t host,
101 		     pciio_slot_t guest)
102 {
103     pcibr_hints_t           hint = pcibr_hints_get(xconn_vhdl, 1);
104 
105     if (hint)
106 	hint->ph_host_slot[guest] = host + 1;
107     else
108 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
109 		    "pcibr_hints_dualslot: pcibr_hints_get failed\n"));
110 }
111 
112 void
pcibr_hints_intr_bits(vertex_hdl_t xconn_vhdl,pcibr_intr_bits_f * xxx_intr_bits)113 pcibr_hints_intr_bits(vertex_hdl_t xconn_vhdl,
114 		      pcibr_intr_bits_f *xxx_intr_bits)
115 {
116     pcibr_hints_t           hint = pcibr_hints_get(xconn_vhdl, 1);
117 
118     if (hint)
119 	hint->ph_intr_bits = xxx_intr_bits;
120     else
121 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
122 		    "pcibr_hints_intr_bits: pcibr_hints_get failed\n"));
123 }
124 
125 void
pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl,rrb_alloc_funct_t rrb_alloc_funct)126 pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct)
127 {
128     pcibr_hints_t           hint = pcibr_hints_get(xconn_vhdl, 1);
129 
130     if (hint)
131 	hint->rrb_alloc_funct = rrb_alloc_funct;
132 }
133 
134 void
pcibr_hints_handsoff(vertex_hdl_t xconn_vhdl)135 pcibr_hints_handsoff(vertex_hdl_t xconn_vhdl)
136 {
137     pcibr_hints_t           hint = pcibr_hints_get(xconn_vhdl, 1);
138 
139     if (hint)
140 	hint->ph_hands_off = 1;
141     else
142 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
143 		    "pcibr_hints_handsoff: pcibr_hints_get failed\n"));
144 }
145 
146 void
pcibr_hints_subdevs(vertex_hdl_t xconn_vhdl,pciio_slot_t slot,uint64_t subdevs)147 pcibr_hints_subdevs(vertex_hdl_t xconn_vhdl,
148 		    pciio_slot_t slot,
149 		    uint64_t subdevs)
150 {
151     arbitrary_info_t        ainfo = 0;
152     char                    sdname[16];
153     vertex_hdl_t            pconn_vhdl = GRAPH_VERTEX_NONE;
154 
155     sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot);
156     (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl);
157     if (pconn_vhdl == GRAPH_VERTEX_NONE) {
158 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
159 		    "pcibr_hints_subdevs: hwgraph_path_create failed\n"));
160 	return;
161     }
162     hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo);
163     if (ainfo == 0) {
164 	uint64_t                *subdevp;
165 
166 	NEW(subdevp);
167 	if (!subdevp) {
168 	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
169 			"pcibr_hints_subdevs: subdev ptr alloc failed\n"));
170 	    return;
171 	}
172 	*subdevp = subdevs;
173 	hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp);
174 	hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo);
175 	if (ainfo == (arbitrary_info_t) subdevp)
176 	    return;
177 	DEL(subdevp);
178 	if (ainfo == (arbitrary_info_t) NULL) {
179 	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
180 			"pcibr_hints_subdevs: null subdevs ptr\n"));
181 	    return;
182 	}
183 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
184 		    "pcibr_subdevs_get: dup subdev add_LBL\n"));
185     }
186     *(uint64_t *) ainfo = subdevs;
187 }
188