Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/sgi-ip27/ip27-xtalk.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 1999, 2000 Ralf Baechle ([email protected])
4
* Copyright (C) 1999, 2000 Silcon Graphics, Inc.
5
* Copyright (C) 2004 Christoph Hellwig.
6
*
7
* Generic XTALK initialization code
8
*/
9
10
#include <linux/kernel.h>
11
#include <linux/smp.h>
12
#include <linux/platform_device.h>
13
#include <linux/platform_data/sgi-w1.h>
14
#include <linux/platform_data/xtalk-bridge.h>
15
#include <asm/sn/addrs.h>
16
#include <asm/sn/types.h>
17
#include <asm/sn/klconfig.h>
18
#include <asm/pci/bridge.h>
19
#include <asm/xtalk/xtalk.h>
20
21
22
#define XBOW_WIDGET_PART_NUM 0x0
23
#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
24
#define BASE_XBOW_PORT 8 /* Lowest external port */
25
26
static void bridge_platform_create(nasid_t nasid, int widget, int masterwid)
27
{
28
struct xtalk_bridge_platform_data *bd;
29
struct sgi_w1_platform_data *wd;
30
struct platform_device *pdev_wd;
31
struct platform_device *pdev_bd;
32
struct resource w1_res;
33
unsigned long offset;
34
35
offset = NODE_OFFSET(nasid);
36
37
wd = kzalloc(sizeof(*wd), GFP_KERNEL);
38
if (!wd) {
39
pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
40
return;
41
}
42
43
snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
44
offset + (widget << SWIN_SIZE_BITS));
45
46
memset(&w1_res, 0, sizeof(w1_res));
47
w1_res.start = offset + (widget << SWIN_SIZE_BITS) +
48
offsetof(struct bridge_regs, b_nic);
49
w1_res.end = w1_res.start + 3;
50
w1_res.flags = IORESOURCE_MEM;
51
52
pdev_wd = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
53
if (!pdev_wd) {
54
pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
55
goto err_kfree_wd;
56
}
57
if (platform_device_add_resources(pdev_wd, &w1_res, 1)) {
58
pr_warn("xtalk:n%d/%x bridge failed to add platform resources.\n", nasid, widget);
59
goto err_put_pdev_wd;
60
}
61
if (platform_device_add_data(pdev_wd, wd, sizeof(*wd))) {
62
pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget);
63
goto err_put_pdev_wd;
64
}
65
if (platform_device_add(pdev_wd)) {
66
pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget);
67
goto err_put_pdev_wd;
68
}
69
/* platform_device_add_data() duplicates the data */
70
kfree(wd);
71
72
bd = kzalloc(sizeof(*bd), GFP_KERNEL);
73
if (!bd) {
74
pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
75
goto err_unregister_pdev_wd;
76
}
77
pdev_bd = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
78
if (!pdev_bd) {
79
pr_warn("xtalk:n%d/%x bridge create out of memory\n", nasid, widget);
80
goto err_kfree_bd;
81
}
82
83
84
bd->bridge_addr = RAW_NODE_SWIN_BASE(nasid, widget);
85
bd->intr_addr = BIT_ULL(47) + 0x01800000 + PI_INT_PEND_MOD;
86
bd->nasid = nasid;
87
bd->masterwid = masterwid;
88
89
bd->mem.name = "Bridge PCI MEM";
90
bd->mem.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
91
bd->mem.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
92
bd->mem.flags = IORESOURCE_MEM;
93
bd->mem_offset = offset;
94
95
bd->io.name = "Bridge PCI IO";
96
bd->io.start = offset + (widget << SWIN_SIZE_BITS) + BRIDGE_DEVIO0;
97
bd->io.end = offset + (widget << SWIN_SIZE_BITS) + SWIN_SIZE - 1;
98
bd->io.flags = IORESOURCE_IO;
99
bd->io_offset = offset;
100
101
if (platform_device_add_data(pdev_bd, bd, sizeof(*bd))) {
102
pr_warn("xtalk:n%d/%x bridge failed to add platform data.\n", nasid, widget);
103
goto err_put_pdev_bd;
104
}
105
if (platform_device_add(pdev_bd)) {
106
pr_warn("xtalk:n%d/%x bridge failed to add platform device.\n", nasid, widget);
107
goto err_put_pdev_bd;
108
}
109
/* platform_device_add_data() duplicates the data */
110
kfree(bd);
111
pr_info("xtalk:n%d/%x bridge widget\n", nasid, widget);
112
return;
113
114
err_put_pdev_bd:
115
platform_device_put(pdev_bd);
116
err_kfree_bd:
117
kfree(bd);
118
err_unregister_pdev_wd:
119
platform_device_unregister(pdev_wd);
120
return;
121
err_put_pdev_wd:
122
platform_device_put(pdev_wd);
123
err_kfree_wd:
124
kfree(wd);
125
return;
126
}
127
128
static int probe_one_port(nasid_t nasid, int widget, int masterwid)
129
{
130
widgetreg_t widget_id;
131
xwidget_part_num_t partnum;
132
133
widget_id = *(volatile widgetreg_t *)
134
(RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
135
partnum = XWIDGET_PART_NUM(widget_id);
136
137
switch (partnum) {
138
case BRIDGE_WIDGET_PART_NUM:
139
case XBRIDGE_WIDGET_PART_NUM:
140
bridge_platform_create(nasid, widget, masterwid);
141
break;
142
default:
143
pr_info("xtalk:n%d/%d unknown widget (0x%x)\n",
144
nasid, widget, partnum);
145
break;
146
}
147
148
return 0;
149
}
150
151
static int xbow_probe(nasid_t nasid)
152
{
153
lboard_t *brd;
154
klxbow_t *xbow_p;
155
unsigned masterwid, i;
156
157
/*
158
* found xbow, so may have multiple bridges
159
* need to probe xbow
160
*/
161
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8);
162
if (!brd)
163
return -ENODEV;
164
165
xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW);
166
if (!xbow_p)
167
return -ENODEV;
168
169
/*
170
* Okay, here's a xbow. Let's arbitrate and find
171
* out if we should initialize it. Set enabled
172
* hub connected at highest or lowest widget as
173
* master.
174
*/
175
#ifdef WIDGET_A
176
i = HUB_WIDGET_ID_MAX + 1;
177
do {
178
i--;
179
} while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
180
(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
181
#else
182
i = HUB_WIDGET_ID_MIN - 1;
183
do {
184
i++;
185
} while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
186
(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
187
#endif
188
189
masterwid = i;
190
if (nasid != XBOW_PORT_NASID(xbow_p, i))
191
return 1;
192
193
for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) {
194
if (XBOW_PORT_IS_ENABLED(xbow_p, i) &&
195
XBOW_PORT_TYPE_IO(xbow_p, i))
196
probe_one_port(nasid, i, masterwid);
197
}
198
199
return 0;
200
}
201
202
static void xtalk_probe_node(nasid_t nasid)
203
{
204
volatile u64 hubreg;
205
xwidget_part_num_t partnum;
206
widgetreg_t widget_id;
207
208
hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
209
210
/* check whether the link is up */
211
if (!(hubreg & IIO_LLP_CSR_IS_UP))
212
return;
213
214
widget_id = *(volatile widgetreg_t *)
215
(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
216
partnum = XWIDGET_PART_NUM(widget_id);
217
218
switch (partnum) {
219
case BRIDGE_WIDGET_PART_NUM:
220
bridge_platform_create(nasid, 0x8, 0xa);
221
break;
222
case XBOW_WIDGET_PART_NUM:
223
case XXBOW_WIDGET_PART_NUM:
224
pr_info("xtalk:n%d/0 xbow widget\n", nasid);
225
xbow_probe(nasid);
226
break;
227
default:
228
pr_info("xtalk:n%d/0 unknown widget (0x%x)\n", nasid, partnum);
229
break;
230
}
231
}
232
233
static int __init xtalk_init(void)
234
{
235
nasid_t nasid;
236
237
for_each_online_node(nasid)
238
xtalk_probe_node(nasid);
239
240
return 0;
241
}
242
arch_initcall(xtalk_init);
243
244