Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/mca/mca-legacy.c
15109 views
1
/* -*- mode: c; c-basic-offset: 8 -*- */
2
3
/*
4
* MCA bus support functions for legacy (2.4) API.
5
*
6
* Legacy API means the API that operates in terms of MCA slot number
7
*
8
* (C) 2002 James Bottomley <[email protected]>
9
*
10
**-----------------------------------------------------------------------------
11
**
12
** This program is free software; you can redistribute it and/or modify
13
** it under the terms of the GNU General Public License as published by
14
** the Free Software Foundation; either version 2 of the License, or
15
** (at your option) any later version.
16
**
17
** This program is distributed in the hope that it will be useful,
18
** but WITHOUT ANY WARRANTY; without even the implied warranty of
19
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
** GNU General Public License for more details.
21
**
22
** You should have received a copy of the GNU General Public License
23
** along with this program; if not, write to the Free Software
24
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
**
26
**-----------------------------------------------------------------------------
27
*/
28
29
#include <linux/module.h>
30
#include <linux/device.h>
31
#include <linux/mca-legacy.h>
32
#include <asm/io.h>
33
34
/* NOTE: This structure is stack allocated */
35
struct mca_find_adapter_info {
36
int id;
37
int slot;
38
struct mca_device *mca_dev;
39
};
40
41
/* The purpose of this iterator is to loop over all the devices and
42
* find the one with the smallest slot number that's just greater than
43
* or equal to the required slot with a matching id */
44
static int mca_find_adapter_callback(struct device *dev, void *data)
45
{
46
struct mca_find_adapter_info *info = data;
47
struct mca_device *mca_dev = to_mca_device(dev);
48
49
if(mca_dev->pos_id != info->id)
50
return 0;
51
52
if(mca_dev->slot < info->slot)
53
return 0;
54
55
if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
56
info->mca_dev = mca_dev;
57
58
return 0;
59
}
60
61
/**
62
* mca_find_adapter - scan for adapters
63
* @id: MCA identification to search for
64
* @start: starting slot
65
*
66
* Search the MCA configuration for adapters matching the 16bit
67
* ID given. The first time it should be called with start as zero
68
* and then further calls made passing the return value of the
69
* previous call until %MCA_NOTFOUND is returned.
70
*
71
* Disabled adapters are not reported.
72
*/
73
74
int mca_find_adapter(int id, int start)
75
{
76
struct mca_find_adapter_info info;
77
78
if(id == 0xffff)
79
return MCA_NOTFOUND;
80
81
info.slot = start;
82
info.id = id;
83
info.mca_dev = NULL;
84
85
for(;;) {
86
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
87
88
if(info.mca_dev == NULL)
89
return MCA_NOTFOUND;
90
91
if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
92
break;
93
94
/* OK, found adapter but it was disabled. Go around
95
* again, excluding the slot we just found */
96
97
info.slot = info.mca_dev->slot + 1;
98
info.mca_dev = NULL;
99
}
100
101
return info.mca_dev->slot;
102
}
103
EXPORT_SYMBOL(mca_find_adapter);
104
105
/*--------------------------------------------------------------------*/
106
107
/**
108
* mca_find_unused_adapter - scan for unused adapters
109
* @id: MCA identification to search for
110
* @start: starting slot
111
*
112
* Search the MCA configuration for adapters matching the 16bit
113
* ID given. The first time it should be called with start as zero
114
* and then further calls made passing the return value of the
115
* previous call until %MCA_NOTFOUND is returned.
116
*
117
* Adapters that have been claimed by drivers and those that
118
* are disabled are not reported. This function thus allows a driver
119
* to scan for further cards when some may already be driven.
120
*/
121
122
int mca_find_unused_adapter(int id, int start)
123
{
124
struct mca_find_adapter_info info = { 0 };
125
126
if (!MCA_bus || id == 0xffff)
127
return MCA_NOTFOUND;
128
129
info.slot = start;
130
info.id = id;
131
info.mca_dev = NULL;
132
133
for(;;) {
134
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
135
136
if(info.mca_dev == NULL)
137
return MCA_NOTFOUND;
138
139
if(info.mca_dev->status != MCA_ADAPTER_DISABLED
140
&& !info.mca_dev->driver_loaded)
141
break;
142
143
/* OK, found adapter but it was disabled or already in
144
* use. Go around again, excluding the slot we just
145
* found */
146
147
info.slot = info.mca_dev->slot + 1;
148
info.mca_dev = NULL;
149
}
150
151
return info.mca_dev->slot;
152
}
153
EXPORT_SYMBOL(mca_find_unused_adapter);
154
155
/* NOTE: stack allocated structure */
156
struct mca_find_device_by_slot_info {
157
int slot;
158
struct mca_device *mca_dev;
159
};
160
161
static int mca_find_device_by_slot_callback(struct device *dev, void *data)
162
{
163
struct mca_find_device_by_slot_info *info = data;
164
struct mca_device *mca_dev = to_mca_device(dev);
165
166
if(mca_dev->slot == info->slot)
167
info->mca_dev = mca_dev;
168
169
return 0;
170
}
171
172
struct mca_device *mca_find_device_by_slot(int slot)
173
{
174
struct mca_find_device_by_slot_info info;
175
176
info.slot = slot;
177
info.mca_dev = NULL;
178
179
bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
180
181
return info.mca_dev;
182
}
183
184
/**
185
* mca_read_stored_pos - read POS register from boot data
186
* @slot: slot number to read from
187
* @reg: register to read from
188
*
189
* Fetch a POS value that was stored at boot time by the kernel
190
* when it scanned the MCA space. The register value is returned.
191
* Missing or invalid registers report 0.
192
*/
193
unsigned char mca_read_stored_pos(int slot, int reg)
194
{
195
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
196
197
if(!mca_dev)
198
return 0;
199
200
return mca_device_read_stored_pos(mca_dev, reg);
201
}
202
EXPORT_SYMBOL(mca_read_stored_pos);
203
204
205
/**
206
* mca_read_pos - read POS register from card
207
* @slot: slot number to read from
208
* @reg: register to read from
209
*
210
* Fetch a POS value directly from the hardware to obtain the
211
* current value. This is much slower than mca_read_stored_pos and
212
* may not be invoked from interrupt context. It handles the
213
* deep magic required for onboard devices transparently.
214
*/
215
216
unsigned char mca_read_pos(int slot, int reg)
217
{
218
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
219
220
if(!mca_dev)
221
return 0;
222
223
return mca_device_read_pos(mca_dev, reg);
224
}
225
EXPORT_SYMBOL(mca_read_pos);
226
227
228
/**
229
* mca_write_pos - read POS register from card
230
* @slot: slot number to read from
231
* @reg: register to read from
232
* @byte: byte to write to the POS registers
233
*
234
* Store a POS value directly from the hardware. You should not
235
* normally need to use this function and should have a very good
236
* knowledge of MCA bus before you do so. Doing this wrongly can
237
* damage the hardware.
238
*
239
* This function may not be used from interrupt context.
240
*
241
* Note that this a technically a Bad Thing, as IBM tech stuff says
242
* you should only set POS values through their utilities.
243
* However, some devices such as the 3c523 recommend that you write
244
* back some data to make sure the configuration is consistent.
245
* I'd say that IBM is right, but I like my drivers to work.
246
*
247
* This function can't do checks to see if multiple devices end up
248
* with the same resources, so you might see magic smoke if someone
249
* screws up.
250
*/
251
252
void mca_write_pos(int slot, int reg, unsigned char byte)
253
{
254
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
255
256
if(!mca_dev)
257
return;
258
259
mca_device_write_pos(mca_dev, reg, byte);
260
}
261
EXPORT_SYMBOL(mca_write_pos);
262
263
/**
264
* mca_set_adapter_name - Set the description of the card
265
* @slot: slot to name
266
* @name: text string for the namen
267
*
268
* This function sets the name reported via /proc for this
269
* adapter slot. This is for user information only. Setting a
270
* name deletes any previous name.
271
*/
272
273
void mca_set_adapter_name(int slot, char* name)
274
{
275
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
276
277
if(!mca_dev)
278
return;
279
280
mca_device_set_name(mca_dev, name);
281
}
282
EXPORT_SYMBOL(mca_set_adapter_name);
283
284
/**
285
* mca_mark_as_used - claim an MCA device
286
* @slot: slot to claim
287
* FIXME: should we make this threadsafe
288
*
289
* Claim an MCA slot for a device driver. If the
290
* slot is already taken the function returns 1,
291
* if it is not taken it is claimed and 0 is
292
* returned.
293
*/
294
295
int mca_mark_as_used(int slot)
296
{
297
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
298
299
if(!mca_dev)
300
/* FIXME: this is actually a severe error */
301
return 1;
302
303
if(mca_device_claimed(mca_dev))
304
return 1;
305
306
mca_device_set_claim(mca_dev, 1);
307
308
return 0;
309
}
310
EXPORT_SYMBOL(mca_mark_as_used);
311
312
/**
313
* mca_mark_as_unused - release an MCA device
314
* @slot: slot to claim
315
*
316
* Release the slot for other drives to use.
317
*/
318
319
void mca_mark_as_unused(int slot)
320
{
321
struct mca_device *mca_dev = mca_find_device_by_slot(slot);
322
323
if(!mca_dev)
324
return;
325
326
mca_device_set_claim(mca_dev, 0);
327
}
328
EXPORT_SYMBOL(mca_mark_as_unused);
329
330
331