s390mach.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/s390/kernel/s390mach.c
  3.  *   S/390 machine check handler,
  4.  *            currently only channel-reports are supported
  5.  *
  6.  *  S390 version
  7.  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  8.  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  9.  */
  10. #include <linux/config.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #ifdef CONFIG_SMP
  15. #include <linux/smp.h>
  16. #endif
  17. #include <asm/irq.h>
  18. #include <asm/lowcore.h>
  19. #include <asm/semaphore.h>
  20. #include <asm/s390io.h>
  21. #include <asm/s390dyn.h>
  22. #include <asm/s390mach.h>
  23. #define S390_MACHCHK_DEBUG
  24. static int         s390_machine_check_handler( void * parm );
  25. static void        s390_enqueue_mchchk( mache_t *mchchk );
  26. static mache_t    *s390_dequeue_mchchk( void );
  27. static void        s390_enqueue_free_mchchk( mache_t *mchchk );
  28. static mache_t    *s390_dequeue_free_mchchk( void );
  29. static int         s390_collect_crw_info( void );
  30. static mache_t    *mchchk_queue_head = NULL;
  31. static mache_t    *mchchk_queue_tail = NULL;
  32. static mache_t    *mchchk_queue_free = NULL;
  33. static crwe_t     *crw_buffer_anchor = NULL;
  34. static spinlock_t  mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
  35. static spinlock_t  crw_queue_lock    = SPIN_LOCK_UNLOCKED;
  36. static struct semaphore s_sem;
  37. /*
  38.  * s390_init_machine_check
  39.  *
  40.  * initialize machine check handling
  41.  */
  42. void s390_init_machine_check( void )
  43. {
  44. crwe_t  *pcrwe;  /* CRW buffer element pointer */
  45. mache_t *pmache;   /* machine check element pointer */
  46. init_MUTEX_LOCKED( &s_sem );
  47. pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL);
  48. if ( pcrwe )
  49. {
  50. int i;
  51. crw_buffer_anchor = pcrwe;
  52. for ( i=0; i < MAX_CRW_PENDING-1; i++)
  53. {
  54. pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t));
  55.     pcrwe            = pcrwe->crwe_next;
  56. } /* endfor */
  57. pcrwe->crwe_next = NULL;
  58. }
  59. else
  60. {
  61. panic( "s390_init_machine_check : unable to obtain memoryn");
  62. } /* endif */
  63. pmache = kmalloc( MAX_MACH_PENDING * sizeof( mache_t), GFP_KERNEL);
  64. if ( pmache )
  65. {
  66. int i;
  67. for ( i=0; i < MAX_MACH_PENDING; i++)
  68. {
  69. s390_enqueue_free_mchchk( pmache );
  70.    pmache = (mache_t *)((unsigned long)pmache + sizeof(mache_t));
  71. } /* endfor */
  72. }
  73. else
  74. {
  75. panic( "s390_init_machine_check : unable to obtain memoryn");
  76. } /* endif */
  77. #ifdef S390_MACHCHK_DEBUG
  78. printk( "init_mach : starting machine check handlern");
  79. #endif
  80. kernel_thread( s390_machine_check_handler, &s_sem, CLONE_FS | CLONE_FILES);
  81. ctl_clear_bit( 14, 25 );  // disable damage MCH 
  82. #if 1
  83.    ctl_set_bit( 14, 28 ); // enable channel report MCH
  84. #endif
  85. #ifdef S390_MACHCHK_DEBUG
  86. printk( "init_mach : machine check buffer : head = %08Xn",
  87.             (unsigned)&mchchk_queue_head);
  88. printk( "init_mach : machine check buffer : tail = %08Xn",
  89.             (unsigned)&mchchk_queue_tail);
  90. printk( "init_mach : machine check buffer : free = %08Xn",
  91.             (unsigned)&mchchk_queue_free);
  92. printk( "init_mach : CRW entry buffer anchor = %08Xn",
  93.             (unsigned)&crw_buffer_anchor);
  94. printk( "init_mach : machine check handler readyn");
  95. #endif
  96. return;
  97. }
  98. /*
  99.  * s390_do_machine_check
  100.  *
  101.  * mchine check pre-processor, collecting the machine check info,
  102.  *  queueing it and posting the machine check handler for processing.
  103.  */
  104. void s390_do_machine_check( void )
  105. {
  106. int      crw_count;
  107. mcic_t   mcic;
  108. #ifdef S390_MACHCHK_DEBUG
  109. printk( "s390_do_machine_check : starting ...n");
  110. #endif
  111. memcpy( &mcic,
  112.         &S390_lowcore.mcck_interruption_code,
  113.         sizeof(__u64));
  114.  
  115. if ( mcic.mcc.mcd.cp ) // CRW pending ?
  116. {
  117. crw_count = s390_collect_crw_info();
  118. if ( crw_count )
  119. {
  120. up( &s_sem );
  121. } /* endif */
  122. } /* endif */
  123. #ifdef S390_MACHCHK_DEBUG
  124. printk( "s390_do_machine_check : done n");
  125. #endif
  126. return;
  127. }
  128. /*
  129.  * s390_machine_check_handler
  130.  *
  131.  * machine check handler, dequeueing machine check entries
  132.  *  and processing them
  133.  */
  134. static int s390_machine_check_handler( void *parm)
  135. {
  136. struct semaphore *sem = parm;
  137. unsigned long     flags;
  138. mache_t          *pmache;
  139. int               found = 0;
  140.         /* set name to something sensible */
  141.         strcpy (current->comm, "kmcheck");
  142.         /* block all signals */
  143.         sigfillset(&current->blocked);
  144. #ifdef S390_MACHCHK_DEBUG
  145. printk( "mach_handler : readyn");
  146. #endif
  147. do {
  148. #ifdef S390_MACHCHK_DEBUG
  149. printk( "mach_handler : waiting for wakeupn");
  150. #endif
  151. down_interruptible( sem );
  152. #ifdef S390_MACHCHK_DEBUG
  153. printk( "nmach_handler : wakeup ... n");
  154. #endif
  155. found = 0; /* init ... */
  156. __save_flags( flags );
  157. __cli();
  158. do {
  159. pmache = s390_dequeue_mchchk();
  160. if ( pmache )
  161. {
  162. found = 1;
  163. if ( pmache->mcic.mcc.mcd.cp )
  164. {
  165. crwe_t *pcrwe_n;
  166. crwe_t *pcrwe_h;
  167. s390_do_crw_pending( pmache->mc.crwe );
  168. pcrwe_h = pmache->mc.crwe;
  169. pcrwe_n = pmache->mc.crwe->crwe_next;
  170. pmache->mcic.mcc.mcd.cp = 0;
  171. pmache->mc.crwe         = NULL;
  172. spin_lock( &crw_queue_lock);
  173. while ( pcrwe_h )
  174. {
  175. pcrwe_h->crwe_next = crw_buffer_anchor;
  176. crw_buffer_anchor  = pcrwe_h;
  177. pcrwe_h            = pcrwe_n;
  178. if ( pcrwe_h != NULL )
  179. pcrwe_n = pcrwe_h->crwe_next;
  180. } /* endwhile */
  181. spin_unlock( &crw_queue_lock);
  182. } /* endif */
  183. s390_enqueue_free_mchchk( pmache );
  184. }
  185. else
  186. {
  187. // unconditional surrender ...
  188. #ifdef S390_MACHCHK_DEBUG
  189. printk( "mach_handler : nothing to do, sleepingn");
  190. #endif
  191. } /* endif */
  192. } while ( pmache );
  193. __restore_flags( flags );
  194. } while ( 1 );
  195. return( 0);
  196. }
  197. /*
  198.  * s390_dequeue_mchchk
  199.  *
  200.  * Dequeue an entry from the machine check queue
  201.  *
  202.  * Note : The queue elements provide for a double linked list.
  203.  *  We dequeue entries from the tail, and enqueue entries to
  204.  *  the head.
  205.  *
  206.  */
  207. static mache_t *s390_dequeue_mchchk( void )
  208. {
  209. mache_t *qe;
  210. spin_lock( &mchchk_queue_lock );
  211. qe = mchchk_queue_tail;
  212.    if ( qe != NULL )
  213.    {
  214.       mchchk_queue_tail = qe->prev;
  215.       if ( mchchk_queue_tail != NULL )
  216.       {
  217. mchchk_queue_tail->next = NULL;
  218. }
  219. else
  220.       {
  221. mchchk_queue_head = NULL;
  222.       } /* endif */
  223. } /* endif */
  224. spin_unlock( &mchchk_queue_lock );
  225. return qe;
  226. }
  227. /*
  228.  * s390_enqueue_mchchk
  229.  *
  230.  * Enqueue an entry to the machine check queue.
  231.  *
  232.  * Note : The queue elements provide for a double linked list.
  233.  *  We enqueue entries to the head, and dequeue entries from
  234.  *  the tail.
  235.  *
  236.  */
  237. static void s390_enqueue_mchchk( mache_t *pmache )
  238. {
  239. spin_lock( &mchchk_queue_lock );
  240. if ( pmache != NULL )
  241. {
  242. if ( mchchk_queue_head == NULL )  /* first element */
  243. {
  244.    pmache->next      = NULL;
  245.    pmache->prev      = NULL;
  246. mchchk_queue_head = pmache;
  247. mchchk_queue_tail = pmache;
  248. }
  249. else /* new head */
  250. {
  251.    pmache->prev            = NULL;
  252. pmache->next            = mchchk_queue_head;
  253. mchchk_queue_head->prev = pmache;
  254. mchchk_queue_head       = pmache;
  255. } /* endif */
  256. } /* endif */
  257. spin_unlock( &mchchk_queue_lock );
  258. return;
  259. }
  260. /*
  261.  * s390_enqueue_free_mchchk
  262.  *
  263.  * Enqueue a free entry to the free queue.
  264.  *
  265.  * Note : While the queue elements provide for a double linked list,
  266.  *  the free queue entries are only concatenated by means of a
  267.  *  single linked list (forward concatenation).
  268.  *
  269.  */
  270. static void s390_enqueue_free_mchchk( mache_t *pmache )
  271. {
  272. if ( pmache != NULL)
  273. {
  274. memset( pmache, '', sizeof( mache_t ));
  275. spin_lock( &mchchk_queue_lock );
  276. pmache->next = mchchk_queue_free;
  277. mchchk_queue_free = pmache;
  278. spin_unlock( &mchchk_queue_lock );
  279. } /* endif */
  280. return;
  281. }
  282. /*
  283.  * s390_dequeue_free_mchchk
  284.  *
  285.  * Dequeue an entry from the free queue.
  286.  *
  287.  * Note : While the queue elements provide for a double linked list,
  288.  *  the free queue entries are only concatenated by means of a
  289.  *  single linked list (forward concatenation).
  290.  *
  291.  */
  292. static mache_t *s390_dequeue_free_mchchk( void )
  293. {
  294. mache_t *qe;
  295. spin_lock( &mchchk_queue_lock );
  296. qe = mchchk_queue_free;
  297. if ( qe != NULL )
  298. {
  299. mchchk_queue_free = qe->next;
  300. } /* endif */
  301. spin_unlock( &mchchk_queue_lock );
  302. return qe;
  303. }
  304. /*
  305.  * s390_collect_crw_info
  306.  *
  307.  * Retrieve CRWs. If a CRW was found a machine check element
  308.  *  is dequeued from the free chain, filled and enqueued to
  309.  *  be processed.
  310.  *
  311.  * The function returns the number of CRWs found.
  312.  *
  313.  * Note : We must always be called disabled ...
  314.  */
  315. static int s390_collect_crw_info( void )
  316. {
  317. crw_t    tcrw;     /* temporarily holds a CRW */
  318. int      ccode;    /* condition code from stcrw() */
  319. crwe_t  *pcrwe;    /* pointer to CRW buffer entry */
  320. mache_t *pmache = NULL; /* ptr to mchchk entry */
  321. int      chain  = 0;    /* indicate chaining */
  322. crwe_t  *pccrw  = NULL; /* ptr to current CRW buffer entry */
  323. int      count  = 0;    /* CRW count */
  324. #ifdef S390_MACHCHK_DEBUG
  325. printk( "crw_info : looking for CRWs ...n");
  326. #endif
  327. do
  328. {
  329. ccode = stcrw( (__u32 *)&tcrw);
  330. if ( ccode == 0 )
  331. {
  332. count++;
  333. #ifdef S390_MACHCHK_DEBUG
  334. printk( "crw_info : CRW reports "
  335.         "slct=%d, oflw=%d, chn=%d, "
  336.         "rsc=%X, anc=%d, erc=%X, "
  337.         "rsid=%Xn",
  338.         tcrw.slct,
  339.         tcrw.oflw,
  340.         tcrw.chn,
  341.         tcrw.rsc,
  342.         tcrw.anc,
  343.         tcrw.erc,
  344.         tcrw.rsid );
  345. #endif
  346. /*
  347.  * Dequeue a CRW entry from the free chain
  348.  *  and process it ...
  349.  */
  350. spin_lock( &crw_queue_lock );
  351. pcrwe = crw_buffer_anchor;
  352. if ( pcrwe == NULL )
  353. {
  354. spin_unlock( &crw_queue_lock );
  355. printk( KERN_CRIT"crw_info : "
  356.         "no CRW buffer entries availablen");
  357. break;
  358. } /* endif */
  359. crw_buffer_anchor = pcrwe->crwe_next;
  360. pcrwe->crwe_next  = NULL;
  361. spin_unlock( &crw_queue_lock );
  362. memcpy( &(pcrwe->crw), &tcrw, sizeof(crw_t));
  363. /*
  364.  * If it is the first CRW, chain it to the mchchk
  365.  *  buffer entry, otherwise to the last CRW entry.
  366.  */
  367. if ( chain == 0 )
  368. {
  369. pmache = s390_dequeue_free_mchchk();
  370. if ( pmache != NULL )
  371. {
  372. memset( pmache, '', sizeof(mache_t));
  373. pmache->mcic.mcc.mcd.cp = 1;
  374. pmache->mc.crwe         = pcrwe;
  375. pccrw                   = pcrwe;
  376. }
  377. else
  378. {
  379. panic( "crw_info : "
  380.        "unable to dequeue "
  381.        "free mchchk buffer");
  382. } /* endif */
  383. }
  384. else
  385. {
  386. pccrw->crwe_next = pcrwe;
  387. pccrw            = pcrwe;
  388. } /* endif */
  389. if ( pccrw->crw.chn )
  390. {
  391. #ifdef S390_MACHCHK_DEBUG
  392. printk( "crw_info : "
  393.         "chained CRWs pending ...nn");
  394. #endif
  395. chain = 1;
  396. }
  397. else
  398. {
  399. chain = 0;
  400. /*
  401.  * We can enqueue the mchchk buffer if
  402.  *  there aren't more CRWs chained.
  403.  */
  404. s390_enqueue_mchchk( pmache);
  405. } /* endif */
  406. } /* endif */
  407. } while ( ccode == 0 );
  408. return( count );
  409. }