Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
19 KiB

4 years ago
  1. //#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/mpagent.c,v 1.1 1995/05/19 11:22:19 flo Exp $")
  2. /*++
  3. Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG
  4. Copyright (c) 1991 Microsoft Corporation
  5. Module Name:
  6. mpagent.c
  7. Abstract:
  8. This module implements the routines dealing with the SNI MP Agent on
  9. SNI system.
  10. Environment:
  11. Kernel mode
  12. --*/
  13. #include "halp.h"
  14. #include "MPagent.h"
  15. typedef struct _mp_agent{
  16. /* Register Register
  17. * name number offset description
  18. * ---------- ---- ------ --------------------------------- */
  19. ULONG cpureg; /* 0x00 0x000 configuration cpu register */
  20. ULONG invalid_0;
  21. ULONG cpuda1reg; /* 0x01 0x008 general register */
  22. ULONG invalid_1;
  23. ULONG msgdata; /* 0x02 0x010 data for message passing */
  24. ULONG invalid_2;
  25. ULONG msgstatus; /* 0x03 0x018 message status */
  26. ULONG invalid_3;
  27. ULONG snooper; /* 0x04 0x020 snooper configuration register */
  28. ULONG invalid_4;
  29. ULONG tagreg; /* 0x05 0x028 tag ram R/W index register */
  30. ULONG invalid_5;
  31. ULONG snpadreg; /* 0x06 0x030 adress of first MBus fatal error */
  32. ULONG invalid_6;
  33. ULONG itpend; /* 0x07 0x038 Interrupt register */
  34. ULONG invalid_7;
  35. ULONG datamsg1; /* 0x08 0x040 data message register 1 */
  36. ULONG invalid_8;
  37. ULONG datamsg2; /* 0x09 0x048 data message register 2 */
  38. ULONG invalid_9;
  39. ULONG datamsg3; /* 0x0a 0x050 data message register 3 */
  40. ULONG invalid_a;
  41. ULONG lppreg0; /* 0x0b 0x058 LPP register cpu 0 */
  42. ULONG invalid_b;
  43. ULONG lppreg1; /* 0x0c 0x060 LPP register cpu 1 */
  44. ULONG invalid_c;
  45. ULONG lppreg2; /* 0x0d 0x068 LPP register cpu 2 */
  46. ULONG invalid_d;
  47. ULONG lppreg3; /* 0x0e 0x070 LPP register cpu 3 */
  48. ULONG invalid_e;
  49. ULONG tagram; /* 0x0f 0x078 tag ram R/W register */
  50. ULONG invalid_f;
  51. ULONG crefcpt; /* 0x10 0x080 cpu general read counter register */
  52. ULONG invalid_10;
  53. ULONG ctarcpt; /* 0x11 0x088 cpu programmable access counter */
  54. ULONG invalid_11;
  55. ULONG srefcpt; /* 0x12 0x090 snooper general read counter reg. */
  56. ULONG invalid_12;
  57. ULONG starcpt; /* 0x13 0x098 snooper programmable accesscounter*/
  58. ULONG invalid_13;
  59. ULONG linkreg; /* 0x14 0x0a0 link register */
  60. ULONG invalid_14;
  61. ULONG software1; /* 0x15 0x0a8 software register1 */
  62. ULONG invalid_15;
  63. ULONG msgaddress; /* 0x16 0x0b0 address message register */
  64. ULONG invalid_16;
  65. ULONG mem_operator; /* 0x17 0x0b8 operator internal burst register */
  66. ULONG invalid_17;
  67. ULONG software2; /* 0x18 0x0c0 software register2 */
  68. }MP_AGENT, *PMP_AGENT;
  69. #define mpagent ((volatile PMP_AGENT) MPA_BASE_ADDRESS) // mpagent address
  70. VOID
  71. HalpInitMPAgent(
  72. IN ULONG Number
  73. )
  74. /*++
  75. Routine Description:
  76. This routine initializes the MutiProcessor_Agent chipset:
  77. - reset an eventual MP_Agent fatal error,
  78. - enable message passing (send/receive),
  79. - fix routage for internal IT -> external IT,
  80. - enable the internal interrupts,
  81. - fix the mask for wanted external interrupts,
  82. - disable Low Process Priority mode for
  83. external interrupts,
  84. - enable cache replace operator and update the
  85. 'cache_rpl_buffer' global variable with a KSEG0
  86. 4 Mb reserved address.
  87. Arguments:
  88. Number : Logical number of the processor to be initialised
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. ULONG reg;
  94. #if DBG
  95. PCR->HalReserved[0] =0;
  96. #endif
  97. //
  98. // set up the snooper register
  99. //
  100. reg = READ_REGISTER_ULONG(&(mpagent->snooper)); /* read the current value */
  101. reg |= (MPA_ENRCVMESS | /* enable message receiving */
  102. MPA_RSTSNPERR | /* reset an eventual old MP_Agent fatal error */
  103. MPA_ENLINK | /* enable read and link command */
  104. MPA_ENCOHREQ | /* enable coherency on the MP bus for this agent */
  105. 0); /* keep other fields */
  106. WRITE_REGISTER_ULONG(&(mpagent->snooper), reg);
  107. reg &= ~(MPA_RSTSNPERR); /* enable new interrupt for MP_Agent fatal error */
  108. WRITE_REGISTER_ULONG(&(mpagent->snooper), reg);
  109. //
  110. // cpu1reg register
  111. //
  112. reg = READ_REGISTER_ULONG(&(mpagent->cpuda1reg)); /* read the current value */
  113. reg &= ~(MPA_ENDIRECT | /* disable LPP mechanism */
  114. MPA_ENTESTIT | /* disable interrupt test mode (interrupts from MPBus) */
  115. MPA_SELITI_MASK | /* reset old internal interrupt routage */
  116. 0); /* keep other fields */
  117. reg |= MPA_SELITI_SR_IP5; /* send internal interrupts on external interrupt SR_IP5*/
  118. WRITE_REGISTER_ULONG(&(mpagent->cpuda1reg), reg);
  119. //
  120. // cpureg register
  121. //
  122. reg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */
  123. reg &= ~(MPA_ENINT_MASK | /* reset old values for interrupts */
  124. MPA_INTCONF_MASK| /* force falling edge for all interrupts */
  125. MPA_ENSHARED | /* don't put optimal mode for KERNEL */
  126. 0); /* keep other fields */
  127. reg |= (MPA_ENSENDMSG | /* enable sending message */
  128. MPA_ENINT_MPBERR | /* enable internal interrupt for MP_Agent fatal error */
  129. MPA_ENINT_ITMSG1 | /* enable internal interrupt for message1 register */
  130. MPA_ENINT_ITMSG2 | /* enable internal interrupt for message2 register */
  131. MPA_ENINT_ITMSG3 | /* enable internal interrupt for message3 register */
  132. MPA_INTMSK | /* mask sent during external request stage */
  133. 0); /* keep other fields */
  134. //
  135. // external Interrupts routing in the MP Agent
  136. //
  137. if (Number == 0) {
  138. //
  139. // For this release, the device interrupts are only processed by bootcpu.
  140. //
  141. reg |= (MPA_ENINT_SR_IP3
  142. | MPA_ENINT_SR_IP4
  143. | MPA_ENINT_SR_IP5
  144. // | MPA_ENINT_SR_IP6
  145. // | MPA_ENINT_SR_IP7
  146. );
  147. } else {
  148. //
  149. // place something special to non boot cpu here ...
  150. //
  151. reg |= (MPA_ENINT_SR_IP6 // Enable Extra Clock Interrupts (IP6)
  152. // | MPA_ENINT_SR_IP7
  153. );
  154. }
  155. WRITE_REGISTER_ULONG(&(mpagent->cpureg), reg);
  156. //
  157. // clear pending interrupts by reading of the message registers
  158. //
  159. reg = READ_REGISTER_ULONG(&(mpagent->datamsg1));
  160. reg = READ_REGISTER_ULONG(&(mpagent->datamsg2));
  161. reg = READ_REGISTER_ULONG(&(mpagent->datamsg3));
  162. reg = ((MPAGENT_RESERVED & // put the reserved physical address (4Mb long)
  163. MPA_OP_ADDR_MASK) |
  164. MPA_OP_ENABLE); // enable the operator
  165. WRITE_REGISTER_ULONG(&(mpagent->mem_operator), reg);
  166. }
  167. VOID
  168. HalpInit2MPAgent(
  169. )
  170. /*++
  171. Routine Description:
  172. This routine initializes the MutiProcessor_Agent chipset:
  173. - enable net interrupt on the current processor
  174. Arguments:
  175. None
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. ULONG reg;
  181. //
  182. // cpureg register
  183. //
  184. reg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */
  185. reg |= MPA_ENINT_SR_IP7;
  186. WRITE_REGISTER_ULONG(&(mpagent->cpureg), reg);
  187. }
  188. VOID
  189. HalRequestIpi(
  190. IN ULONG CpuMask
  191. )
  192. /*++
  193. Routine Description:
  194. This routine requests an interprocessor interrupt on a set of processors.
  195. That is done by using the message passing facility of the MPagent.
  196. N.B. This routine must ensure that the interrupt is posted at the target
  197. processor(s) before returning.
  198. Arguments:
  199. Mask - Supplies the set of processors that are sent an interprocessor
  200. interrupt.
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. ULONG physmask, cpt;
  206. PRESTART_BLOCK NextRestartBlock;
  207. // CpuMask is a logical mask. We must use a mask with the physical
  208. // numbers of cpus to communicate with the MP_Agent.
  209. physmask = 0;cpt = 0;
  210. NextRestartBlock = SYSTEM_BLOCK->RestartBlock;
  211. while (NextRestartBlock != NULL) {
  212. if (CpuMask & ( 1 << cpt))
  213. physmask |= (1 << (NextRestartBlock->ProcessorId));
  214. ++cpt ; NextRestartBlock = NextRestartBlock->NextRestartBlock;
  215. }
  216. HalpSendIpi(physmask,MPA_KERNEL_MESSAGE);
  217. }
  218. VOID
  219. HalpSendIpi(
  220. IN ULONG pcpumask,
  221. IN ULONG msg_data
  222. )
  223. /*++
  224. Routine Description:
  225. This routine sends an interprocessor interrupt on a set of processors.
  226. That is done by using the message passing facility of the MPagent.
  227. N.B. This routine must ensure that the interrupt is posted at the target
  228. processor(s) before returning.
  229. Arguments:
  230. pcpumask - Supplies the set of processors that are sent an interprocessor
  231. interrupt. It contains physical numbers.
  232. msg_data _ Supplies the kind of message to be send : kernel demand or HAL internal demand.
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. KIRQL OldIrql;
  238. LONG msg_retries, watchdog;
  239. ULONG msg_address, msg_status;
  240. if (!pcpumask || !HalpIsMulti) {
  241. return;
  242. }
  243. //
  244. // Raise IRQL to ??? level.
  245. //
  246. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  247. //
  248. // form the Message Address register (Message register 1 / 2, CPUMask)
  249. // The SNI MP Agent supports up to 4 CPU's
  250. //
  251. msg_address = (pcpumask & MPA_CPUTARGET_MASK) | MPA_REGTARGET_MSG1;
  252. msg_data = ((msg_data << 24) | (pcpumask & MPA_CPUTARGET_MASK));
  253. msg_retries = MPA_MSG_RETRY;
  254. /*
  255. * Go on, just do it.
  256. * If at first you don't succeed, then try, try and try again...
  257. */
  258. do {
  259. watchdog = 10;
  260. WRITE_REGISTER_ULONG(&(mpagent->msgaddress), msg_address);
  261. WRITE_REGISTER_ULONG(&(mpagent->msgdata), msg_data);
  262. /*
  263. * so, what happened? poll either until we know or the watchdog counter runs out
  264. */
  265. do {
  266. KeStallExecutionProcessor(5);
  267. //
  268. // read the message status register
  269. //
  270. msg_status = READ_REGISTER_ULONG(&(mpagent->msgstatus));
  271. } while (((msg_status & MPA_VALSTAT) == 0) && watchdog--);
  272. if ((msg_status & MPA_VALSTAT) != MPA_VALSTAT) {
  273. #if DBG
  274. DbgPrint("HAL: Watchdog Overrun !\n");
  275. #endif
  276. KeStallExecutionProcessor(100);
  277. continue;
  278. } else {
  279. //
  280. // okay, we have a Valid status bit
  281. // so test of busy
  282. if ((msg_status & MPA_ERRMSG) == 0) {
  283. //
  284. // all is fine
  285. //
  286. KeLowerIrql(OldIrql);
  287. return;
  288. } else {
  289. #if DBGG
  290. DbgPrint("HAL: Could not deliver IPI (busy)!\n");
  291. #endif
  292. msg_retries = MPA_MSG_RETRY;
  293. KeStallExecutionProcessor(100);
  294. continue;
  295. }
  296. }
  297. KeStallExecutionProcessor(10);
  298. } while (--msg_retries); /* message aborted, try again */
  299. KeLowerIrql(OldIrql);
  300. #if DBG
  301. DbgPrint("HAL: WARNING - Could not deliver IPI (0x%x) MPA->status: 0x%2x! \n", msg_data, msg_status);
  302. DbgPrint("HAL: pending Interupts: 0x%8x\n", READ_REGISTER_ULONG(&(mpagent->itpend)));
  303. #endif
  304. return;
  305. }
  306. VOID
  307. HalpProcessIpi(
  308. IN struct _KTRAP_FRAME *TrapFrame
  309. )
  310. /*++
  311. Routine Description:
  312. This routine is entered as the result of an IP5 interrupt. This function
  313. will looks at the MPagent to see if an IPI has just occurred.
  314. Arguments:
  315. None.
  316. Return Value:
  317. --*/
  318. {
  319. ULONG itpend, msg_data;
  320. itpend = READ_REGISTER_ULONG(&(mpagent->itpend)); /* first read the interrupt pending MP_Agent register */
  321. if (itpend & MPA_INTN_ITMSG1) {
  322. //
  323. // reading the message register clears the interrupt from the MP Agent
  324. //
  325. msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg1)) >> 24);
  326. HalpCheckSpuriousInt();
  327. if (msg_data == MPA_KERNEL_MESSAGE) {
  328. KeIpiInterrupt(TrapFrame);
  329. return;
  330. }
  331. if (msg_data == MPA_RESTART_MESSAGE) {
  332. if (PCR->Number) {
  333. #if DBGG
  334. DbgPrint("Got shutdown message ...\n");
  335. #endif
  336. // remove this processor from the list of active processors
  337. HalpActiveProcessors &= (~(PCR->SetMember));
  338. HalSweepDcache(); // flush the value above for the other processors
  339. // call a firmware funtion to stop slave cpu's which will break the caches
  340. ((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->reinit_slave();
  341. } else {
  342. HalpBootCpuRestart();
  343. }
  344. }
  345. #if DBGG
  346. DbgPrint("HAL: Warning: unknown IPI Interrupt Message in Register 1\n");
  347. #endif
  348. }
  349. if ((itpend & MPA_INTN_INT_MASK) == 0) {
  350. ULONG snooper = READ_REGISTER_ULONG(&(mpagent->snooper));
  351. //
  352. // None of the MP Agent internal Interrupts was pending --> just return
  353. //
  354. HalpCheckSpuriousInt();
  355. #if DBGG
  356. DbgPrint("HAL: Got unexpected Interrupt in the MP Agent - \nnothing is pending [0x%08x] snooper 0x%08x cause: 0x%08x status: 0x%08xspurious = %d \n",
  357. itpend, snooper, HalpGetCauseRegister(), HalpGetStatusRegister(),HalpCheckSpuriousInt());
  358. #endif
  359. return;
  360. }
  361. if (itpend & MPA_INTN_MPBERR) {
  362. //
  363. // Fatal Error
  364. //
  365. ULONG snooper, cpureg ;
  366. #if DBGG
  367. ULONG snpadreg, data, data2 ;
  368. DbgPrint("HAL: FATAL - Fatal Error Interrupt in the MP Agent !!! \n");
  369. #endif
  370. cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read the current value */
  371. cpureg &= ~(MPA_ENINT_MPBERR /* disable interrupt for MP_Agent fatal error */
  372. ); /* keep other fields */
  373. WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // write the new value in the MP_Agent register /
  374. snooper = READ_REGISTER_ULONG(&(mpagent->snooper)); // read the current snooper register value/
  375. #if DBGG
  376. snpadreg = READ_REGISTER_ULONG(&(mpagent->snpadreg));
  377. WRITE_REGISTER_ULONG( &(mpagent->tagreg),snpadreg);
  378. data = READ_REGISTER_ULONG(&(mpagent->tagram));
  379. data2 = HalpGetTaglo( data | KSEG0_BASE);
  380. DbgPrint("snooper %08x Bad Address was: 0x%08x \nData in the Tag Copy is: 0x%08x\nData in the TagLo is: 0x%08x \n",snooper, snpadreg, data, data2);
  381. #endif
  382. snooper |= MPA_RSTSNPERR; /* reset this MP_Agent fatal error */
  383. WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */
  384. snooper &= ~(MPA_RSTSNPERR); /* stop reseting this MP_Agent fatal error */
  385. WRITE_REGISTER_ULONG(&(mpagent->snooper), snooper); /* write the new value in the MP_Agent register */
  386. HalpCheckSpuriousInt();
  387. return;
  388. }
  389. if (itpend & MPA_INTN_ITMSG2) {
  390. //
  391. // reading the message register clears the interrupt from the MP Agent
  392. // we use message register 2 for the restart message
  393. //
  394. msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg2)) >> 24);
  395. HalpCheckSpuriousInt();
  396. #if DBGG
  397. DbgPrint("HAL: Warning: IPI Interrupt Message in Register 2\n");
  398. #endif
  399. return;
  400. }
  401. if (itpend & MPA_INTN_ITMSG3) {
  402. //
  403. // reading the message register clears the interrupt from the MP Agent
  404. //
  405. msg_data = (READ_REGISTER_ULONG(&(mpagent->datamsg3)) >> 24);
  406. HalpCheckSpuriousInt();
  407. #if DBGG
  408. DbgPrint("HAL: Warning: IPI Interrupt Message in Register 3\n");
  409. #endif
  410. return;
  411. }
  412. }
  413. ULONG
  414. HalpGetMyAgent(
  415. VOID
  416. )
  417. {
  418. ULONG reg;
  419. reg = READ_REGISTER_ULONG(&(mpagent->snooper)); /* read the current value */
  420. return( (reg & MPA_ADAGT_MASK) >> MPA_ADAGT_SHIFT);
  421. }
  422. /*
  423. * ======================================================================
  424. *
  425. * NAME: mpa_check_spurious_intr
  426. *
  427. * PURPOSE: Fix a bug in the MP_Agent which sometimes make a bad
  428. * update of the cause register.
  429. *
  430. * PARAMETERS: none
  431. *
  432. * RETURNS: = 0 no possible spurious interrupt
  433. * 1 possible spurious interrupt
  434. *
  435. * ======================================================================
  436. */
  437. BOOLEAN HalpCheckSpuriousInt(VOID)
  438. {
  439. ULONG itpend, causeit, pending;
  440. ULONG cpureg, tempreg;
  441. if ( HalpProcessorId != MPAGENT) {
  442. return 0;
  443. }
  444. itpend = READ_REGISTER_ULONG(&(mpagent->itpend)); /* read the interrupt pending MP_Agent register */
  445. causeit = (itpend & MPA_OINTN_MASKGEN) >> MPA_OINTN_SHIFT;
  446. pending = (itpend & MPA_INTN_MASKGEN );
  447. if (causeit != pending) {
  448. /*
  449. * Need a second filter for pending interrupt which don't take care
  450. * of real enabled interrupt mask of cpureg.
  451. */
  452. cpureg = READ_REGISTER_ULONG(&(mpagent->cpureg)); /* read interrupt enable mask for this cpu */
  453. pending &= (
  454. ((cpureg & (MPA_ENINT_SR_IP3 |
  455. MPA_ENINT_SR_IP4 |
  456. MPA_ENINT_SR_IP5 |
  457. MPA_ENINT_SR_IP6 |
  458. MPA_ENINT_SR_IP7)) >> MPA_ENINT_MASKSHIFT)
  459. |
  460. ((cpureg & (MPA_ENINT_ITMSG1 |
  461. MPA_ENINT_ITMSG2 |
  462. MPA_ENINT_ITMSG3 |
  463. MPA_ENINT_MPBERR)) >> (MPA_ENINT_MASKSHIFT-1))
  464. );
  465. if (causeit != pending) {
  466. /*
  467. * There is sometimes an MP_Agent interrupt with values different in
  468. * MPA_INTN_... = 0 and MPA_OINTN_....
  469. * That means : The cause register has been updated with a wrong value!
  470. * We need to force a new update of the cause register to avoid looping
  471. * on this interrupt until a new external interrupt happens.
  472. */
  473. if (cpureg & MPA_INTCONF_SR_IP8) {
  474. tempreg = (cpureg & (~MPA_INTCONF_SR_IP8)) | MPA_ENINT_SR_IP8;
  475. } else {
  476. tempreg = (cpureg | MPA_INTCONF_SR_IP8 | MPA_ENINT_SR_IP8);
  477. }
  478. WRITE_REGISTER_ULONG(&(mpagent->cpureg), tempreg); // write the new value in the MP_Agent register /
  479. WRITE_REGISTER_ULONG(&(mpagent->cpureg), cpureg); // Restore initial value
  480. #if DBG
  481. ++PCR->HalReserved[0] ;
  482. #endif
  483. return 1; /* Possible spurious ! */
  484. }
  485. }
  486. return 0; /* No possible spurious ! */
  487. }