source: trunk/src/opengl/glide/swlibs/pcilib/fxmsr.c

Last change on this file was 2887, checked in by sandervl, 26 years ago

Created swlibs dir

File size: 12.4 KB
Line 
1/*
2 ** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
3 ** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
4 ** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
5 ** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
6 ** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
7 ** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
8 ** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
9 ** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
10 **
11 ** USE, DUPLICATION OR DISCLOSURE BY THE GOVERNMENT IS SUBJECT TO
12 ** RESTRICTIONS AS SET FORTH IN SUBDIVISION (C)(1)(II) OF THE RIGHTS IN
13 ** TECHNICAL DATA AND COMPUTER SOFTWARE CLAUSE AT DFARS 252.227-7013,
14 ** AND/OR IN SIMILAR OR SUCCESSOR CLAUSES IN THE FAR, DOD OR NASA FAR
15 ** SUPPLEMENT. UNPUBLISHED RIGHTS RESERVED UNDER THE COPYRIGHT LAWS OF
16 ** THE UNITED STATES.
17 **
18 ** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
19 **
20 **
21 ** $Revision: 1.1 $
22 ** $Date: 2000-02-25 00:33:55 $
23 **
24 */
25
26#include <stdlib.h>
27#include <stdio.h>
28
29#include <3dfx.h>
30#define FX_DLL_DEFINITION
31#include <fxdll.h>
32#include <fxmemmap.h>
33#include "fxpci.h"
34#include "pcilib.h"
35
36#if __WIN32__
37#include <windows.h>
38#include "fxw32.h"
39#elif defined(__DOS32__)
40#include <fxdpmi.h>
41#endif
42
43/*---------------------------------------------------------------------------
44**
45** MTRR Code
46**
47** It's possible that this code belongs elsewhere, but since it
48** communicates with the VXD, it needs to be in here for now. If at
49** some later date, we rearchitecth the whole VXD thing, then we
50** should revisit this code and find a good place for it.
51*----------------------------------------------------------------------------*/
52
53#define MTRR_VALID 0x800
54#define MTRR_BASE_FIRST 0x200
55#define MTRR_MASK_FIRST 0x201
56#define MTRR_BASE_LAST 0x20e
57#define MTRR_MASK_LAST 0x20f
58
59/* NB: Although the intel docs say that the last 2 mtrr's are reserved for
60 * os use only win9x doesn't play nice and claims entries in the 'user' range.
61 * To make things as happy as possible we search the entire mtrr range.
62 */
63#define MTRR_FIRST 0
64#define MTRR_LAST 7
65
66/* AMD K6 has only two MTRRs */
67#define MTRR_LAST_AMDK6 1
68
69#define MTRRPHYSBASE2MSR(mtrr) ((mtrr << 1) + MTRR_BASE_FIRST)
70#define MTRRPHYSMASK2MSR(mtrr) ((mtrr << 1) + MTRR_MASK_FIRST)
71#define MSR2MTRR(msr) (((msr) - 0x201) >> 1)
72
73/*
74** A Note On MTRRs:
75**
76** MTRRs are special cases of MSRs (model specific registers). They
77** work in pairs, specified as follows (the number is the MSR number):
78*/
79#define MTRR_PHYSBASE_0 0x200
80#define MTRR_PHYSMASK_0 0x201
81#define MTRR_PHYSBASE_1 0x202
82#define MTRR_PHYSMASK_1 0x203
83#define MTRR_PHYSBASE_2 0x204
84#define MTRR_PHYSMASK_2 0x205
85#define MTRR_PHYSBASE_3 0x206
86#define MTRR_PHYSMASK_3 0x207
87#define MTRR_PHYSBASE_4 0x208
88#define MTRR_PHYSMASK_4 0x209
89#define MTRR_PHYSBASE_5 0x20a
90#define MTRR_PHYSMASK_5 0x20b
91
92/*
93** The MTRRs of the AMD K6 are not compatible to the MTRRs on Intel
94** processors. There are two MTRRs which are in a single MSR.
95*/
96
97#define MTRR_MSR_AMDK6 0xC0000085
98
99/*
100** So, the PHYSBASE_N is the base address for a particular MTRR and
101** uses a whole MSR. It has the type encoded in the bottom three
102** nibbles (12 bits).
103**
104** The PHYSMASK_N is the physical mask for a particular MTRR and uses
105** the MSR immediately following the MSR which specifies the physical
106** base and type.
107**
108** See the headers of the functions genPhysBase and genPhysMask to
109** find out how to generate the PhysBase value and the PhysMask
110** value. If you want to see the place from which this information
111** was obtained, refer to the document Pentium(r) Pro Family
112** Developer's Manual Volume 3: Operating System Writer's Guide,
113** Chpater 11: Memory Cache Control. Note that the terms PhysBase
114** and PhysMask come from there.
115*/
116
117/* genPhysBase - Generate PhysBase
118**
119** MTRRPhysBase:
120** Bits 7:0 Memory Type
121** Bits 11:8 Reserved
122** Bits 35:12 PhysBase
123** Bits 63:36 Reserved
124**
125** The Intel P6 documentation pines away about how the PhysBase field
126** of this register contains an integer power of two multiple of
127** 0x1000, but guess what? The number (if it has a legal value) is
128** already set up that way, so, we just leave it TF alone, and then
129** OR in the type (the types specified in fxpci.h match the Intel
130** P6 mem types indentically).
131*/
132static FxBool
133genPhysBase(FxU32 physBaseAddress, PciMemType type, FxU32 *physBase)
134{
135 FxBool
136 ret = FXFALSE;
137
138 /* Validate type */
139 switch (type) {
140 case PciMemTypeUncacheable:
141 case PciMemTypeWriteCombining:
142 case PciMemTypeWriteThrough:
143 case PciMemTypeWriteProtected:
144 case PciMemTypeWriteback:
145 break;
146 default:
147 /* Invalid Type */
148 return ret;
149 break;
150 }
151
152 /* Validate base address -- make sure it's on a 4K boundary */
153 if (physBaseAddress & 0xfff) {
154 /* Invalid start address */
155 return ret;
156 }
157
158 /*
159 ** We now have a valid size and type.
160 ** Generate the MTRR value for PhysBase.
161 */
162 *physBase = physBaseAddress | type;
163
164 return (ret = FXTRUE);
165
166} /* genPhysBase */
167
168/* genPhysMask - Generate PhysMask:
169**
170** MTRRPhysMask:
171** Bits 10:0 Reserved
172** Bit 11 Valid
173** Bits 35:12 PhysMask
174** Bits 63:36 Reserved
175**
176** The PhysMask field works as follows:
177** from Bit 12 to bit 35, there are N zeros, and m ones, where n is
178** the power of two to multiply by 4069 to get the size you want,
179** and m is 35 - n. i.e.:
180**
181** size = 2^n * 0x1000
182** m = 35 - m
183**
184** Since we have the lowBit from above, we know which power of 2
185** the size is, so we simply need to shift it right by 12 to see
186** how many of the bits between 12 an 35 are 0. We then shift
187** 0xffffffff left by that many bits to get the right mask.
188**
189*/
190static FxBool
191genPhysMask(FxU32 physSize, FxU32 *physMask)
192{
193 FxBool
194 ret = FXFALSE;
195
196 FxU32
197 bitRes,
198 lowBit;
199
200 /*
201 ** Validate size
202 **
203 ** Size must be an integer power of 2, and it must be greater than
204 ** 4K (4096d, 1000h, 10000o, 1000000000000b :-)
205 */
206
207 /* Do it this way instead of a mask, so we find zero if it's there */
208 if (physSize < 0x1000) {
209 /* invalid size */
210 return ret;
211 }
212
213 /*
214 ** Make sure it's an integer power of 2:
215 ** Any power of 2 (except 0) ANDed with its
216 ** integer predecessor is always 0.
217 */
218 if (physSize & (physSize - 1)) {
219 return ret;
220 }
221
222 /* Find the lowest bit set in physSize */
223 lowBit = 11;
224 do {
225 ++lowBit;
226 bitRes = (physSize >> lowBit) & 1;
227 } while ((bitRes == 0) && (lowBit < 0x20));
228
229
230 /* See above for explanation of 0x800 (2**11) */
231 *physMask = (0xffffffff << lowBit) | MTRR_VALID;
232
233 return (ret = FXTRUE);
234
235} /* genPhysMask */
236
237/* Computes bit pattern to program into a K6-style MTRR based on the desired
238** memory range base address, size, and type. Returns FXFALSE if memory type
239** unsupported, block size out of range, or block size not power of 2, or
240** base address not multiple of block size.
241*/
242
243static FxBool
244genMTRRvalAmdK6(FxU32 physBaseAddress, FxU32 physSize, PciMemType type, FxU32 *MTRRval)
245{
246 FxBool retVal = FXFALSE;
247 FxU32 memTypeBits = 0;
248 FxU32 physAddrMask;
249
250 /* Validate memory type */
251
252 if (type == PciMemTypeUncacheable) {
253 memTypeBits = 0x1;
254 }
255 else if (type == PciMemTypeWriteCombining) {
256 memTypeBits = 0x2;
257 }
258 else {
259 return retVal;
260 }
261
262 /* Validate memory range size */
263
264 if (physSize < 128*1024) { /* make sure size >= 128 K */
265 return retVal;
266 }
267
268 if (physSize & (physSize - 1)) { /* make sure size is power of two */
269 return retVal;
270 }
271
272 /* Validate base address */
273
274 if (physBaseAddress % physSize) { /* make sure base is multiple of size */
275 return retVal;
276 }
277
278 /* Convert the range size into a mask */
279
280 physAddrMask = 0x7FFF;
281 physSize >>=18; /* 128K --> 0, 256K --> 1, etc */
282 while (physSize) {
283 physAddrMask <<= 1;
284 physSize >>= 1;
285 }
286
287 /* Now mask: 128K => 7FFF, 256K => 7FFE, 512K => 7FFC, ... , 4G => 0000 */
288
289 *MTRRval = (((physBaseAddress >> 17) & 0x7FFF) << 17) |
290 (physAddrMask & 0x7FFF) << 2 |
291 memTypeBits;
292
293 retVal = FXTRUE;
294
295 return retVal;
296}
297
298/*
299** pciFindMTRRMatch - find an MTRR that matches this one.
300**
301** We return the MTRR number which is a special-case MSR calculated
302** in the following manner:
303**
304** (matchBaseMSR - baseMTRR0) >> 2
305*/
306FX_EXPORT FxBool FX_CSTYLE
307pciFindMTRRMatch(FxU32 physBaseAddress, FxU32 physSize,
308 PciMemType type, FxU32 *mtrrNum)
309{
310 FxBool
311 res,
312 foundMSR = FXFALSE,
313 rVal = FXFALSE;
314
315 FxU32
316 lMTRR,
317 physBase, physMask;
318
319 MSRInfo
320 inS, outS;
321
322 /* Get PhysBase */
323 res = genPhysBase(physBaseAddress, type, &physBase);
324
325 if (res == FXFALSE)
326 return rVal;
327
328 /* Get PhysMask */
329 res = genPhysMask(physSize, &physMask);
330
331 if (res == FXFALSE)
332 return rVal;
333
334 inS.msrNum = MTRR_BASE_FIRST;
335
336 lMTRR = 0;
337
338 do {
339 DOGETMSR(inS,outS);
340
341 if (outS.msrLo == physBase) {
342 inS.msrNum++;
343
344 DOGETMSR(inS, outS);
345
346 if (outS.msrLo == physMask) {
347 *mtrrNum = MSR2MTRR(inS.msrNum);
348 foundMSR = FXTRUE;
349 }
350 }
351 inS.msrNum++;
352 } while (!foundMSR && (inS.msrNum <= MTRR_BASE_LAST));
353
354 if (foundMSR)
355 rVal = FXTRUE;
356
357 return rVal;
358} /* pciFindMTRRMatch */
359
360/*
361** pciFindFreeMTRR - find an MTRR that matches this one.
362**
363** We return the MTRR number which is a special-case MSR calculated
364** in the following manner:
365**
366** (freeBaseMSR - baseMTRR0) >> 2
367**
368** NOTE: This routine will return the lowest-numbered free MTRR
369*/
370FX_EXPORT FxBool FX_CSTYLE
371pciFindFreeMTRR(FxU32 *mtrrNum)
372{
373 FxBool
374 foundFree = FXFALSE;
375
376 MSRInfo
377 inS, outS;
378
379 for (
380 inS.msrNum = MTRR_BASE_FIRST + 1;
381 (inS.msrNum < MTRR_BASE_LAST + 1) && !foundFree;
382 inS.msrNum += 2
383 ) {
384
385 DOGETMSR(inS, outS);
386
387 if ((outS.msrLo & 0x800) == 0) {
388 foundFree = FXTRUE;
389 *mtrrNum = MSR2MTRR(inS.msrNum);
390 }
391 }
392
393 return foundFree;
394} /* pciFindFreeMTRR */
395
396/*
397** pciSetMTRR - set up a specified MTRR based on physical address, physical
398** size, and type.
399**
400** NOTE: A zero for the physical size results in the MTRR being
401** cleared.
402**
403*/
404FX_EXPORT FxBool FX_CSTYLE
405pciSetMTRR(FxU32 mtrrNum, FxU32 physBaseAddr, FxU32 physSize,
406 PciMemType type)
407{
408 FxBool
409 res,
410 rVal = FXFALSE;
411
412 FxU32
413 physBase, physMask;
414
415 MSRInfo
416 inS, outS;
417
418 if (mtrrNum > MTRR_LAST)
419 return rVal;
420
421
422 inS.msrNum = MTRRPHYSBASE2MSR(mtrrNum);
423
424 if (physSize == 0) {
425 /* Clear the MTRR */
426
427 inS.msrLo = 0x0;
428 inS.msrHi = 0x0;
429
430
431 DOSETMSR(inS, outS);
432
433 inS.msrNum++;
434
435 DOSETMSR(inS, outS);
436
437 } else {
438 /* Generate masks and set the MTRR */
439
440 res = genPhysBase(physBaseAddr, type, &physBase);
441 if (res == FXFALSE)
442 return rVal;
443
444 res = genPhysMask(physSize, &physMask);
445
446 inS.msrLo = physBase;
447 inS.msrHi = 0x0;
448
449 DOSETMSR(inS, outS);
450
451 inS.msrNum++;
452 inS.msrLo = physMask;
453 inS.msrHi = 0xf;
454
455 DOSETMSR(inS, outS);
456 }
457
458 rVal = FXTRUE;
459
460 return rVal;
461} /* pciSetMTRR */
462
463/*
464** pciSetMTRRAmdK6 - set up the specified K6-style MTRR based on physical
465** address, physical size, and type.
466**
467** NOTE: A zero for the physical size results in the MTRR being
468** cleared.
469**
470*/
471FX_EXPORT FxBool FX_CSTYLE
472pciSetMTRRAmdK6(FxU32 mtrrNum, FxU32 physBaseAddr, FxU32 physSize,
473 PciMemType type)
474{
475 FxBool
476 res,
477 rVal = FXFALSE;
478
479 FxU32
480 MTRRval;
481
482 MSRInfo
483 inS, outS;
484
485 if (mtrrNum > MTRR_LAST_AMDK6)
486 return rVal;
487
488 inS.msrNum = MTRR_MSR_AMDK6; /* One MSR for both MTRRs */
489
490 if (physSize == 0) { /* size of 0 implies clear MTRR */
491
492 DOGETMSR (inS, outS);
493
494 inS.msrHi = outS.msrHi;
495 inS.msrLo = outS.msrLo;
496
497 if (mtrrNum) {
498 inS.msrHi = 0x0; /* clear MTRR 1 */
499 }
500 else {
501 inS.msrLo = 0x0; /* clear MTRR 0 */
502 }
503
504 DOSETMSR (inS, outS);
505 } else {
506 /* Generate masks and set the MTRR */
507 res = genMTRRvalAmdK6(physBaseAddr, physSize, type, &MTRRval);
508
509 if (res == FXFALSE)
510 return rVal;
511
512 DOGETMSR (inS, outS);
513
514 inS.msrHi = outS.msrHi;
515 inS.msrLo = outS.msrLo;
516
517 if (mtrrNum) {
518 inS.msrHi = MTRRval; /* program MTRR 1 */
519 }
520 else {
521 inS.msrLo = MTRRval; /* program MTRR 0 */
522 }
523
524 DOSETMSR (inS, outS);
525 }
526
527 rVal = FXTRUE;
528
529 return rVal;
530} /* pciSetMTRRAmdK6 */
531
Note: See TracBrowser for help on using the repository browser.