summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halfire/ppc/fpints.c
blob: e69c0981372f0b6be55d028c1a8810ff3ace7da8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
 * Copyright (c) 1995 FirePower Systems, Inc.
 * DO NOT DISTRIBUTE without permission
 *
 * $RCSfile: fpints.c $
 * $Revision: 1.13 $
 * $Date: 1996/07/13 01:15:58 $
 * $Locker:  $
 */

//	  TITLE("Manipulate Interrupt Request Level")
//++
//
// Module Name:
//
//	FPINTS.C
//
// Abstract:
//
//	This module implements the arrays required to handle interrupt
//	priorities including generation of the arrays, and anything else
//	that is hardware specific interrupt oriented.  This is not intended,
//	in it's original incarnation, to be an OS policy file, merely a hw one.
//
//	The theory of ops is given a set of interrupts ordered by priority, 
//	that is for any occurance of an interrupt, only those interrupts pre-
//	ceding it in the list may now occur.  So, if int 5 is the highest 
//	priority then when it occurrs, no other interrupt will be visible. Any 
//	lesser interrupt may be interruptable by an int 5.  And so on.
//
// Author:
//
//	Bill Rees ( FirePOWER )
//	Sol Kavy ( FirePOWER )
//
// Environment:
//
//	Kernel mode only.
//
// Revision History:
//	16-Jul-95   Created
//
//--
#include "fpdebug.h"
#include "halp.h"
#include "phsystem.h"
#include "fppci.h"
#include "pxpcisup.h"
extern ULONG atoi(PCHAR);

#define MAX_IRQL_NUM	32
#define MAX_VECTORS     32

//
// Note: this is declared poorly in pxsiosup.c and should be
// moved to PCR.
//
extern ULONG registeredInts[];

//
// This array spec's which interrupts go with which devices
// on the host-pci bus ( bus 0, i.e. primary bus ).
//		NOTE: 0xff => no device interrupt provided.
//
UCHAR PciDevicePrimaryInts[MAXIMUM_PCI_SLOTS];

/*
 * Given an IRQL, provide a register mask that sets allowable interrupts
 * and blocks all ints that are set at "lower" priority.
 *
 * This array is automatically generated from the Vector2Irql array by the
 * HalpSetIntPriorityMask() call in fpints.c.  For each entry in the V2I array
 * that sits at an IRQL or above, it's interrupt bit is or'd into the Irql2Mask
 * value.  For example, at irql 0, almost every entry in the V2I array has an
 * irql greater than 0 ( except for the reserved interrupts ) so the mask value
 * in the Irql2Mask array has nearly every bit turned on.  Conversely, at IRQL
 * 24, only a few interrupts have irql values above 21 ( ints 0, 1, 22, 23,
 * 28, 29, 30, 31 )
 *
 */
ULONG Irql2Mask[MAX_IRQL_NUM];

/*
 *	This array matches an IRQL to an Interrupt Vector.  Since the array is
 *	indexed by interrupt vector, there can be a many interrupts to single IRQL
 *	mapping allowing interrupts to share IRQL settings.  IRQLs determine
 *	relative operational order such that any code operating at any irql, will
 *	block code from a lower priority from occuring and in turn this same code
 *	can be interrupted by code trying to run at a higher priority.
 *	
 *	So this array becomes a prioritization of interrupts, determining which
 *	interrupts will block each other or not block each other.  In this case,
 *	a higher number means higher priority hence blocking more interrupts.
 *	
 *	explanation on how this array is used is above the Irql2Mask[] declaration.
 *	
 */
ULONG Vector2Irql[MAX_VECTORS] = {
		26,	// int 0 (Timer) is IRQL 26 so it blocks most other interrupts:
		25, // int 1 (KEYBD) blocks all other ISA devices except RTC.

		24, // int 2 is the cascade bit so all interrupts on the cascaded
			// interrupt controller ( 8259 ) are higher priority than the
			// rest of the interrupts on the master interrupt controller.

		15, // int 3 (COM2) is on the master but after the slave ints, so it 
			// blocks only those ints left on the master chip.

		14, // int 4 (COM1) is lower priority than com 2.
		13, // int 5 Display:
        12, // int 6 Floppy:
        11, // int 7 Parallel:
		23, // int 8 (RTC):	First int on Slave: only ints 0,1,2 are higher pri.
		22, // int 9:
		21,	// int 10 (AUDIO).
		20,	// int 11:
		19,	// int 12 Mouse int.  Lower than keyboard.
		18,	// int 13 old scsi
		17,	// int 14 old enet:
		16, // int 15:
		00,	// 			reserved: hence lowest priority
		00,	// 			reserved: hence lowest priority
		00,	// 			reserved: hence lowest priority
		00,	// 			reserved: hence lowest priority
		00,	// int 20  |
		00,	// int 21  |
        00, // int 22  |
		00,	// int 23  - PCI interrupts configured dynamically from the I2C
		00,	// int 24  |
		00, // int 25  |
        00, // int 26  |
		00,	// 			reserved: hence lowest priority
		28,	// int 28(CPU)  Set CPU Bus error IRQL to IPI_LEVEL
        28, // int 29(PCI)  Set PCI Bus error IRQL to IPI_LEVEL
		28,	// int 30(MEM/VID) Set MEMORY  error IRQL to IPI_LEVEL
		29	// int 31(IPI)  this is the cpu message level: > clock
};

ULONG LX_Vector2Irql[MAX_VECTORS] = {
		26, // int 0 (Timer) is IRQL 26 so it blocks most other interrupts:
		25, // int 1 (KEYBD) blocks all other ISA devices except RTC.

		24, // int 2 is the cascade bit so all interrupts on the cascaded
		    // interrupt controller ( 8259 ) are higher priority than the
		    // rest of the interrupts on the master interrupt controller.

		15, // int 3 (COM2) is on the master but after the slave ints, so it 
		    // blocks only those ints left on the master chip.

		14, // int 4 (COM1) is lower priority than com 2.
		13, // int 5 Display:
		12, // int 6 Floppy:
		11, // int 7 Parallel:
		23, // int 8 (RTC):	First int on Slave: only ints 0,1,2 are higher pri.
		22, // int 9:
		21, // int 10 (AUDIO).
		20, // int 11:
		19, // int 12 Mouse int.  Lower than keyboard.
		18, // int 13 old scsi
		17, // int 14 old enet:
		16, // int 15:
		00, // 			reserved: hence lowest priority
		00, // 			reserved: hence lowest priority
		00, // 			reserved: hence lowest priority
		00, // 			reserved: hence lowest priority
		23, // int 20 LX: rsrvd ; TX: PCI slot 3
		22, // int 21 LX: IDE A ; TX: PCI slot 2
		21, // int 22 LX: IDE A ; TX: PCI slot 1
		20, // int 23 pci slot 3 IRQL
		19, // int 24 pci slot 2 IRQL
		18, // int 25 pci slot 1 IRQL scsi
		17, // int 26 pci slot 0 IRQL network
		00, // 			reserved: hence lowest priority
		28, // int 28(CPU)  Set CPU Bus error IRQL to IPI_LEVEL
		28, // int 29(PCI)  Set PCI Bus error IRQL to IPI_LEVEL
		28, // int 30(MEM/VID) Set MEMORY  error IRQL to IPI_LEVEL
		29  // int 31(IPI)  this is the cpu message level: > clock
};

// TX_PROTO & LX_PROTO: must reorder the IRQL table
VOID HalpInitializeVector2Irql(VOID)
{
	ULONG irql = 17;    // Start the PCI interrupts at irql 17
	UCHAR slot;
	UCHAR intNum;

	for (slot = 1; slot < MAXIMUM_PCI_SLOTS; slot++) {
	    intNum = PciDevicePrimaryInts[slot];
		if ((intNum != INVALID_INT)  && (intNum < MAX_VECTORS)) {
			Vector2Irql[intNum] = irql;
			irql++;
		}
	}
}

HalpSetIntPriorityMask(VOID)
{
	ULONG irql, vec, Value=0;

	//
	// for each irql, search the Vector2Irql array and generate
	// a mask suitable for writing to the mask register to block
	// interrupts at the given irql.
	//
	for (irql = 0; irql < MAX_IRQL_NUM; irql++) {
		Irql2Mask[irql] = 0;
		for (vec = 0; vec < MAX_VECTORS; vec++) {
			//
			// Turn on bits for interrupts that are still allowed.
			//
			if (Vector2Irql[vec] > irql) {
				Irql2Mask[irql] |= (1 << vec);
			}
		}
	}
	PRNTINTR(HalpDebugPrint("HalpSetIntPriorityMask:  Irql2Mask: 0x%x\n",
		&Irql2Mask[0]));
	return(1);
}


//
// THis array gives the processor affinity for the given interrupt
// vector. Then NT will handle the interrupt on that processor.
// 

ULONG Vector2Affinity[MAX_VECTORS];


//
/*++

Routine Description: void HalpInitProcAffinity ()
	This function sets the processor affinity for the given interrupt
	in the Vector2Affinity array.  If the values are wrong, cpu 0 is 
	set.

Arguments:

	pProcnInts - pointer to the PROCNINTS nvram variable.
	numProc - number of processors in the system.


Return Value:

	void

--*/

void
HalpInitProcAffinity(PCHAR pProcnInts, ULONG NumProc)
{
	ULONG vec,proc;
	CHAR delim = ';';

	if ( NumProc == 1 ) {
		for(vec=0; vec < MAX_VECTORS; vec++) {
			Vector2Affinity[vec] = 1; // cpu 0 always
		}
		HDBG(DBG_MPINTS, 
			HalpDebugPrint("Affinity set to 1 for all vectors\n"););
		return;
	}
	HDBG(DBG_MPINTS,HalpDebugPrint("vector   affinity\n"););
	// multiprocessor but no PROCNINTS given
	// distribute on all processors round robin fashion
	if ( pProcnInts == 0 ) {
		for(vec=0; vec < MAX_VECTORS; vec++) {
			Vector2Affinity[vec] = 1 << (vec%NumProc); // next cpu gets next vec
			HDBG(DBG_MPINTS, 
				HalpDebugPrint("%6d   %6d\n",vec,Vector2Affinity[vec]););
		}
		return;
	}
	// otherwise go with the env variable PROCNINTS in pProcnInts
	for(vec=0; vec < MAX_VECTORS; vec++) {
		if ( *pProcnInts == 0 || *pProcnInts == delim )
			proc = 0;
		else
			proc = atoi(pProcnInts);
		if ( proc >= NumProc )
			proc = (proc % NumProc);
		Vector2Affinity[vec] = 1 << proc;
		while(*pProcnInts  &&  *pProcnInts != ';')
			pProcnInts++; // skip current affinity
		if (*pProcnInts == ';')
			pProcnInts++; // skip delimiter
		HDBG(DBG_MPINTS,
			HalpDebugPrint("%6d   %6d\n",vec,Vector2Affinity[vec]););
	}
	return;
}