voyager_cat.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. /* -*- mode: c; c-basic-offset: 8 -*- */
  2. /* Copyright (C) 1999,2001
  3. *
  4. * Author: J.E.J.Bottomley@HansenPartnership.com
  5. *
  6. * linux/arch/i386/kernel/voyager_cat.c
  7. *
  8. * This file contains all the logic for manipulating the CAT bus
  9. * in a level 5 machine.
  10. *
  11. * The CAT bus is a serial configuration and test bus. Its primary
  12. * uses are to probe the initial configuration of the system and to
  13. * diagnose error conditions when a system interrupt occurs. The low
  14. * level interface is fairly primitive, so most of this file consists
  15. * of bit shift manipulations to send and receive packets on the
  16. * serial bus */
  17. #include <linux/config.h>
  18. #include <linux/types.h>
  19. #include <linux/completion.h>
  20. #include <linux/sched.h>
  21. #include <asm/voyager.h>
  22. #include <asm/vic.h>
  23. #include <linux/ioport.h>
  24. #include <linux/init.h>
  25. #include <linux/slab.h>
  26. #include <linux/delay.h>
  27. #include <asm/io.h>
  28. #ifdef VOYAGER_CAT_DEBUG
  29. #define CDEBUG(x) printk x
  30. #else
  31. #define CDEBUG(x)
  32. #endif
  33. /* the CAT command port */
  34. #define CAT_CMD (sspb + 0xe)
  35. /* the CAT data port */
  36. #define CAT_DATA (sspb + 0xd)
  37. /* the internal cat functions */
  38. static void cat_pack(__u8 *msg, __u16 start_bit, __u8 *data,
  39. __u16 num_bits);
  40. static void cat_unpack(__u8 *msg, __u16 start_bit, __u8 *data,
  41. __u16 num_bits);
  42. static void cat_build_header(__u8 *header, const __u16 len,
  43. const __u16 smallest_reg_bits,
  44. const __u16 longest_reg_bits);
  45. static int cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp,
  46. __u8 reg, __u8 op);
  47. static int cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp,
  48. __u8 reg, __u8 *value);
  49. static int cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes,
  50. __u8 pad_bits);
  51. static int cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  52. __u8 value);
  53. static int cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  54. __u8 *value);
  55. static int cat_subread(voyager_module_t *modp, voyager_asic_t *asicp,
  56. __u16 offset, __u16 len, void *buf);
  57. static int cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp,
  58. __u8 reg, __u8 value);
  59. static int cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp);
  60. static int cat_connect(voyager_module_t *modp, voyager_asic_t *asicp);
  61. static inline const char *
  62. cat_module_name(int module_id)
  63. {
  64. switch(module_id) {
  65. case 0x10:
  66. return "Processor Slot 0";
  67. case 0x11:
  68. return "Processor Slot 1";
  69. case 0x12:
  70. return "Processor Slot 2";
  71. case 0x13:
  72. return "Processor Slot 4";
  73. case 0x14:
  74. return "Memory Slot 0";
  75. case 0x15:
  76. return "Memory Slot 1";
  77. case 0x18:
  78. return "Primary Microchannel";
  79. case 0x19:
  80. return "Secondary Microchannel";
  81. case 0x1a:
  82. return "Power Supply Interface";
  83. case 0x1c:
  84. return "Processor Slot 5";
  85. case 0x1d:
  86. return "Processor Slot 6";
  87. case 0x1e:
  88. return "Processor Slot 7";
  89. case 0x1f:
  90. return "Processor Slot 8";
  91. default:
  92. return "Unknown Module";
  93. }
  94. }
  95. static int sspb = 0; /* stores the super port location */
  96. int voyager_8slot = 0; /* set to true if a 51xx monster */
  97. voyager_module_t *voyager_cat_list;
  98. /* the I/O port assignments for the VIC and QIC */
  99. static struct resource vic_res = {
  100. .name = "Voyager Interrupt Controller",
  101. .start = 0xFC00,
  102. .end = 0xFC6F
  103. };
  104. static struct resource qic_res = {
  105. .name = "Quad Interrupt Controller",
  106. .start = 0xFC70,
  107. .end = 0xFCFF
  108. };
  109. /* This function is used to pack a data bit stream inside a message.
  110. * It writes num_bits of the data buffer in msg starting at start_bit.
  111. * Note: This function assumes that any unused bit in the data stream
  112. * is set to zero so that the ors will work correctly */
  113. #define BITS_PER_BYTE 8
  114. static void
  115. cat_pack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits)
  116. {
  117. /* compute initial shift needed */
  118. const __u16 offset = start_bit % BITS_PER_BYTE;
  119. __u16 len = num_bits / BITS_PER_BYTE;
  120. __u16 byte = start_bit / BITS_PER_BYTE;
  121. __u16 residue = (num_bits % BITS_PER_BYTE) + offset;
  122. int i;
  123. /* adjust if we have more than a byte of residue */
  124. if(residue >= BITS_PER_BYTE) {
  125. residue -= BITS_PER_BYTE;
  126. len++;
  127. }
  128. /* clear out the bits. We assume here that if len==0 then
  129. * residue >= offset. This is always true for the catbus
  130. * operations */
  131. msg[byte] &= 0xff << (BITS_PER_BYTE - offset);
  132. msg[byte++] |= data[0] >> offset;
  133. if(len == 0)
  134. return;
  135. for(i = 1; i < len; i++)
  136. msg[byte++] = (data[i-1] << (BITS_PER_BYTE - offset))
  137. | (data[i] >> offset);
  138. if(residue != 0) {
  139. __u8 mask = 0xff >> residue;
  140. __u8 last_byte = data[i-1] << (BITS_PER_BYTE - offset)
  141. | (data[i] >> offset);
  142. last_byte &= ~mask;
  143. msg[byte] &= mask;
  144. msg[byte] |= last_byte;
  145. }
  146. return;
  147. }
  148. /* unpack the data again (same arguments as cat_pack()). data buffer
  149. * must be zero populated.
  150. *
  151. * Function: given a message string move to start_bit and copy num_bits into
  152. * data (starting at bit 0 in data).
  153. */
  154. static void
  155. cat_unpack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits)
  156. {
  157. /* compute initial shift needed */
  158. const __u16 offset = start_bit % BITS_PER_BYTE;
  159. __u16 len = num_bits / BITS_PER_BYTE;
  160. const __u8 last_bits = num_bits % BITS_PER_BYTE;
  161. __u16 byte = start_bit / BITS_PER_BYTE;
  162. int i;
  163. if(last_bits != 0)
  164. len++;
  165. /* special case: want < 8 bits from msg and we can get it from
  166. * a single byte of the msg */
  167. if(len == 0 && BITS_PER_BYTE - offset >= num_bits) {
  168. data[0] = msg[byte] << offset;
  169. data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);
  170. return;
  171. }
  172. for(i = 0; i < len; i++) {
  173. /* this annoying if has to be done just in case a read of
  174. * msg one beyond the array causes a panic */
  175. if(offset != 0) {
  176. data[i] = msg[byte++] << offset;
  177. data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);
  178. }
  179. else {
  180. data[i] = msg[byte++];
  181. }
  182. }
  183. /* do we need to truncate the final byte */
  184. if(last_bits != 0) {
  185. data[i-1] &= 0xff << (BITS_PER_BYTE - last_bits);
  186. }
  187. return;
  188. }
  189. static void
  190. cat_build_header(__u8 *header, const __u16 len, const __u16 smallest_reg_bits,
  191. const __u16 longest_reg_bits)
  192. {
  193. int i;
  194. __u16 start_bit = (smallest_reg_bits - 1) % BITS_PER_BYTE;
  195. __u8 *last_byte = &header[len - 1];
  196. if(start_bit == 0)
  197. start_bit = 1; /* must have at least one bit in the hdr */
  198. for(i=0; i < len; i++)
  199. header[i] = 0;
  200. for(i = start_bit; i > 0; i--)
  201. *last_byte = ((*last_byte) << 1) + 1;
  202. }
  203. static int
  204. cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, __u8 op)
  205. {
  206. __u8 parity, inst, inst_buf[4] = { 0 };
  207. __u8 iseq[VOYAGER_MAX_SCAN_PATH], hseq[VOYAGER_MAX_REG_SIZE];
  208. __u16 ibytes, hbytes, padbits;
  209. int i;
  210. /*
  211. * Parity is the parity of the register number + 1 (READ_REGISTER
  212. * and WRITE_REGISTER always add '1' to the number of bits == 1)
  213. */
  214. parity = (__u8)(1 + (reg & 0x01) +
  215. ((__u8)(reg & 0x02) >> 1) +
  216. ((__u8)(reg & 0x04) >> 2) +
  217. ((__u8)(reg & 0x08) >> 3)) % 2;
  218. inst = ((parity << 7) | (reg << 2) | op);
  219. outb(VOYAGER_CAT_IRCYC, CAT_CMD);
  220. if(!modp->scan_path_connected) {
  221. if(asicp->asic_id != VOYAGER_CAT_ID) {
  222. printk("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");
  223. return 1;
  224. }
  225. outb(VOYAGER_CAT_HEADER, CAT_DATA);
  226. outb(inst, CAT_DATA);
  227. if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
  228. CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));
  229. return 1;
  230. }
  231. return 0;
  232. }
  233. ibytes = modp->inst_bits / BITS_PER_BYTE;
  234. if((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {
  235. padbits = BITS_PER_BYTE - padbits;
  236. ibytes++;
  237. }
  238. hbytes = modp->largest_reg / BITS_PER_BYTE;
  239. if(modp->largest_reg % BITS_PER_BYTE)
  240. hbytes++;
  241. CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));
  242. /* initialise the instruction sequence to 0xff */
  243. for(i=0; i < ibytes + hbytes; i++)
  244. iseq[i] = 0xff;
  245. cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);
  246. cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);
  247. inst_buf[0] = inst;
  248. inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);
  249. cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);
  250. #ifdef VOYAGER_CAT_DEBUG
  251. printk("ins = 0x%x, iseq: ", inst);
  252. for(i=0; i< ibytes + hbytes; i++)
  253. printk("0x%x ", iseq[i]);
  254. printk("\n");
  255. #endif
  256. if(cat_shiftout(iseq, ibytes, hbytes, padbits)) {
  257. CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));
  258. return 1;
  259. }
  260. CDEBUG(("CAT SHIFTOUT DONE\n"));
  261. return 0;
  262. }
  263. static int
  264. cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  265. __u8 *value)
  266. {
  267. if(!modp->scan_path_connected) {
  268. if(asicp->asic_id != VOYAGER_CAT_ID) {
  269. CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));
  270. return 1;
  271. }
  272. if(reg > VOYAGER_SUBADDRHI)
  273. outb(VOYAGER_CAT_RUN, CAT_CMD);
  274. outb(VOYAGER_CAT_DRCYC, CAT_CMD);
  275. outb(VOYAGER_CAT_HEADER, CAT_DATA);
  276. *value = inb(CAT_DATA);
  277. outb(0xAA, CAT_DATA);
  278. if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
  279. CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));
  280. return 1;
  281. }
  282. return 0;
  283. }
  284. else {
  285. __u16 sbits = modp->num_asics -1 + asicp->ireg_length;
  286. __u16 sbytes = sbits / BITS_PER_BYTE;
  287. __u16 tbytes;
  288. __u8 string[VOYAGER_MAX_SCAN_PATH], trailer[VOYAGER_MAX_REG_SIZE];
  289. __u8 padbits;
  290. int i;
  291. outb(VOYAGER_CAT_DRCYC, CAT_CMD);
  292. if((padbits = sbits % BITS_PER_BYTE) != 0) {
  293. padbits = BITS_PER_BYTE - padbits;
  294. sbytes++;
  295. }
  296. tbytes = asicp->ireg_length / BITS_PER_BYTE;
  297. if(asicp->ireg_length % BITS_PER_BYTE)
  298. tbytes++;
  299. CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",
  300. tbytes, sbytes, padbits));
  301. cat_build_header(trailer, tbytes, 1, asicp->ireg_length);
  302. for(i = tbytes - 1; i >= 0; i--) {
  303. outb(trailer[i], CAT_DATA);
  304. string[sbytes + i] = inb(CAT_DATA);
  305. }
  306. for(i = sbytes - 1; i >= 0; i--) {
  307. outb(0xaa, CAT_DATA);
  308. string[i] = inb(CAT_DATA);
  309. }
  310. *value = 0;
  311. cat_unpack(string, padbits + (tbytes * BITS_PER_BYTE) + asicp->asic_location, value, asicp->ireg_length);
  312. #ifdef VOYAGER_CAT_DEBUG
  313. printk("value=0x%x, string: ", *value);
  314. for(i=0; i< tbytes+sbytes; i++)
  315. printk("0x%x ", string[i]);
  316. printk("\n");
  317. #endif
  318. /* sanity check the rest of the return */
  319. for(i=0; i < tbytes; i++) {
  320. __u8 input = 0;
  321. cat_unpack(string, padbits + (i * BITS_PER_BYTE), &input, BITS_PER_BYTE);
  322. if(trailer[i] != input) {
  323. CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));
  324. return 1;
  325. }
  326. }
  327. CDEBUG(("cat_getdata DONE\n"));
  328. return 0;
  329. }
  330. }
  331. static int
  332. cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits)
  333. {
  334. int i;
  335. for(i = data_bytes + header_bytes - 1; i >= header_bytes; i--)
  336. outb(data[i], CAT_DATA);
  337. for(i = header_bytes - 1; i >= 0; i--) {
  338. __u8 header = 0;
  339. __u8 input;
  340. outb(data[i], CAT_DATA);
  341. input = inb(CAT_DATA);
  342. CDEBUG(("cat_shiftout: returned 0x%x\n", input));
  343. cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,
  344. &header, BITS_PER_BYTE);
  345. if(input != header) {
  346. CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));
  347. return 1;
  348. }
  349. }
  350. return 0;
  351. }
  352. static int
  353. cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp,
  354. __u8 reg, __u8 value)
  355. {
  356. outb(VOYAGER_CAT_DRCYC, CAT_CMD);
  357. if(!modp->scan_path_connected) {
  358. if(asicp->asic_id != VOYAGER_CAT_ID) {
  359. CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));
  360. return 1;
  361. }
  362. outb(VOYAGER_CAT_HEADER, CAT_DATA);
  363. outb(value, CAT_DATA);
  364. if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
  365. CDEBUG(("cat_senddata: failed to get correct header response to sent data\n"));
  366. return 1;
  367. }
  368. if(reg > VOYAGER_SUBADDRHI) {
  369. outb(VOYAGER_CAT_RUN, CAT_CMD);
  370. outb(VOYAGER_CAT_END, CAT_CMD);
  371. outb(VOYAGER_CAT_RUN, CAT_CMD);
  372. }
  373. return 0;
  374. }
  375. else {
  376. __u16 hbytes = asicp->ireg_length / BITS_PER_BYTE;
  377. __u16 dbytes = (modp->num_asics - 1 + asicp->ireg_length)/BITS_PER_BYTE;
  378. __u8 padbits, dseq[VOYAGER_MAX_SCAN_PATH],
  379. hseq[VOYAGER_MAX_REG_SIZE];
  380. int i;
  381. if((padbits = (modp->num_asics - 1
  382. + asicp->ireg_length) % BITS_PER_BYTE) != 0) {
  383. padbits = BITS_PER_BYTE - padbits;
  384. dbytes++;
  385. }
  386. if(asicp->ireg_length % BITS_PER_BYTE)
  387. hbytes++;
  388. cat_build_header(hseq, hbytes, 1, asicp->ireg_length);
  389. for(i = 0; i < dbytes + hbytes; i++)
  390. dseq[i] = 0xff;
  391. CDEBUG(("cat_senddata: dbytes=%d, hbytes=%d, padbits=%d\n",
  392. dbytes, hbytes, padbits));
  393. cat_pack(dseq, modp->num_asics - 1 + asicp->ireg_length,
  394. hseq, hbytes * BITS_PER_BYTE);
  395. cat_pack(dseq, asicp->asic_location, &value,
  396. asicp->ireg_length);
  397. #ifdef VOYAGER_CAT_DEBUG
  398. printk("dseq ");
  399. for(i=0; i<hbytes+dbytes; i++) {
  400. printk("0x%x ", dseq[i]);
  401. }
  402. printk("\n");
  403. #endif
  404. return cat_shiftout(dseq, dbytes, hbytes, padbits);
  405. }
  406. }
  407. static int
  408. cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  409. __u8 value)
  410. {
  411. if(cat_sendinst(modp, asicp, reg, VOYAGER_WRITE_CONFIG))
  412. return 1;
  413. return cat_senddata(modp, asicp, reg, value);
  414. }
  415. static int
  416. cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  417. __u8 *value)
  418. {
  419. if(cat_sendinst(modp, asicp, reg, VOYAGER_READ_CONFIG))
  420. return 1;
  421. return cat_getdata(modp, asicp, reg, value);
  422. }
  423. static int
  424. cat_subaddrsetup(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
  425. __u16 len)
  426. {
  427. __u8 val;
  428. if(len > 1) {
  429. /* set auto increment */
  430. __u8 newval;
  431. if(cat_read(modp, asicp, VOYAGER_AUTO_INC_REG, &val)) {
  432. CDEBUG(("cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed\n"));
  433. return 1;
  434. }
  435. CDEBUG(("cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x\n", val));
  436. newval = val | VOYAGER_AUTO_INC;
  437. if(newval != val) {
  438. if(cat_write(modp, asicp, VOYAGER_AUTO_INC_REG, val)) {
  439. CDEBUG(("cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed\n"));
  440. return 1;
  441. }
  442. }
  443. }
  444. if(cat_write(modp, asicp, VOYAGER_SUBADDRLO, (__u8)(offset &0xff))) {
  445. CDEBUG(("cat_subaddrsetup: write to SUBADDRLO failed\n"));
  446. return 1;
  447. }
  448. if(asicp->subaddr > VOYAGER_SUBADDR_LO) {
  449. if(cat_write(modp, asicp, VOYAGER_SUBADDRHI, (__u8)(offset >> 8))) {
  450. CDEBUG(("cat_subaddrsetup: write to SUBADDRHI failed\n"));
  451. return 1;
  452. }
  453. cat_read(modp, asicp, VOYAGER_SUBADDRHI, &val);
  454. CDEBUG(("cat_subaddrsetup: offset = %d, hi = %d\n", offset, val));
  455. }
  456. cat_read(modp, asicp, VOYAGER_SUBADDRLO, &val);
  457. CDEBUG(("cat_subaddrsetup: offset = %d, lo = %d\n", offset, val));
  458. return 0;
  459. }
  460. static int
  461. cat_subwrite(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
  462. __u16 len, void *buf)
  463. {
  464. int i, retval;
  465. /* FIXME: need special actions for VOYAGER_CAT_ID here */
  466. if(asicp->asic_id == VOYAGER_CAT_ID) {
  467. CDEBUG(("cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC\n"));
  468. /* FIXME -- This is supposed to be handled better
  469. * There is a problem writing to the cat asic in the
  470. * PSI. The 30us delay seems to work, though */
  471. udelay(30);
  472. }
  473. if((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
  474. printk("cat_subwrite: cat_subaddrsetup FAILED\n");
  475. return retval;
  476. }
  477. if(cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_WRITE_CONFIG)) {
  478. printk("cat_subwrite: cat_sendinst FAILED\n");
  479. return 1;
  480. }
  481. for(i = 0; i < len; i++) {
  482. if(cat_senddata(modp, asicp, 0xFF, ((__u8 *)buf)[i])) {
  483. printk("cat_subwrite: cat_sendata element at %d FAILED\n", i);
  484. return 1;
  485. }
  486. }
  487. return 0;
  488. }
  489. static int
  490. cat_subread(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
  491. __u16 len, void *buf)
  492. {
  493. int i, retval;
  494. if((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
  495. CDEBUG(("cat_subread: cat_subaddrsetup FAILED\n"));
  496. return retval;
  497. }
  498. if(cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_READ_CONFIG)) {
  499. CDEBUG(("cat_subread: cat_sendinst failed\n"));
  500. return 1;
  501. }
  502. for(i = 0; i < len; i++) {
  503. if(cat_getdata(modp, asicp, 0xFF,
  504. &((__u8 *)buf)[i])) {
  505. CDEBUG(("cat_subread: cat_getdata element %d failed\n", i));
  506. return 1;
  507. }
  508. }
  509. return 0;
  510. }
  511. /* buffer for storing EPROM data read in during initialisation */
  512. static __initdata __u8 eprom_buf[0xFFFF];
  513. static voyager_module_t *voyager_initial_module;
  514. /* Initialise the cat bus components. We assume this is called by the
  515. * boot cpu *after* all memory initialisation has been done (so we can
  516. * use kmalloc) but before smp initialisation, so we can probe the SMP
  517. * configuration and pick up necessary information. */
  518. void
  519. voyager_cat_init(void)
  520. {
  521. voyager_module_t **modpp = &voyager_initial_module;
  522. voyager_asic_t **asicpp;
  523. voyager_asic_t *qabc_asic = NULL;
  524. int i, j;
  525. unsigned long qic_addr = 0;
  526. __u8 qabc_data[0x20];
  527. __u8 num_submodules, val;
  528. voyager_eprom_hdr_t *eprom_hdr = (voyager_eprom_hdr_t *)&eprom_buf[0];
  529. __u8 cmos[4];
  530. unsigned long addr;
  531. /* initiallise the SUS mailbox */
  532. for(i=0; i<sizeof(cmos); i++)
  533. cmos[i] = voyager_extended_cmos_read(VOYAGER_DUMP_LOCATION + i);
  534. addr = *(unsigned long *)cmos;
  535. if((addr & 0xff000000) != 0xff000000) {
  536. printk(KERN_ERR "Voyager failed to get SUS mailbox (addr = 0x%lx\n", addr);
  537. } else {
  538. static struct resource res;
  539. res.name = "voyager SUS";
  540. res.start = addr;
  541. res.end = addr+0x3ff;
  542. request_resource(&iomem_resource, &res);
  543. voyager_SUS = (struct voyager_SUS *)
  544. ioremap(addr, 0x400);
  545. printk(KERN_NOTICE "Voyager SUS mailbox version 0x%x\n",
  546. voyager_SUS->SUS_version);
  547. voyager_SUS->kernel_version = VOYAGER_MAILBOX_VERSION;
  548. voyager_SUS->kernel_flags = VOYAGER_OS_HAS_SYSINT;
  549. }
  550. /* clear the processor counts */
  551. voyager_extended_vic_processors = 0;
  552. voyager_quad_processors = 0;
  553. printk("VOYAGER: beginning CAT bus probe\n");
  554. /* set up the SuperSet Port Block which tells us where the
  555. * CAT communication port is */
  556. sspb = inb(VOYAGER_SSPB_RELOCATION_PORT) * 0x100;
  557. VDEBUG(("VOYAGER DEBUG: sspb = 0x%x\n", sspb));
  558. /* now find out if were 8 slot or normal */
  559. if((inb(VIC_PROC_WHO_AM_I) & EIGHT_SLOT_IDENTIFIER)
  560. == EIGHT_SLOT_IDENTIFIER) {
  561. voyager_8slot = 1;
  562. printk(KERN_NOTICE "Voyager: Eight slot 51xx configuration detected\n");
  563. }
  564. for(i = VOYAGER_MIN_MODULE;
  565. i <= VOYAGER_MAX_MODULE; i++) {
  566. __u8 input;
  567. int asic;
  568. __u16 eprom_size;
  569. __u16 sp_offset;
  570. outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
  571. outb(i, VOYAGER_CAT_CONFIG_PORT);
  572. /* check the presence of the module */
  573. outb(VOYAGER_CAT_RUN, CAT_CMD);
  574. outb(VOYAGER_CAT_IRCYC, CAT_CMD);
  575. outb(VOYAGER_CAT_HEADER, CAT_DATA);
  576. /* stream series of alternating 1's and 0's to stimulate
  577. * response */
  578. outb(0xAA, CAT_DATA);
  579. input = inb(CAT_DATA);
  580. outb(VOYAGER_CAT_END, CAT_CMD);
  581. if(input != VOYAGER_CAT_HEADER) {
  582. continue;
  583. }
  584. CDEBUG(("VOYAGER DEBUG: found module id 0x%x, %s\n", i,
  585. cat_module_name(i)));
  586. *modpp = kmalloc(sizeof(voyager_module_t), GFP_KERNEL); /*&voyager_module_storage[cat_count++];*/
  587. if(*modpp == NULL) {
  588. printk("**WARNING** kmalloc failure in cat_init\n");
  589. continue;
  590. }
  591. memset(*modpp, 0, sizeof(voyager_module_t));
  592. /* need temporary asic for cat_subread. It will be
  593. * filled in correctly later */
  594. (*modpp)->asic = kmalloc(sizeof(voyager_asic_t), GFP_KERNEL); /*&voyager_asic_storage[asic_count];*/
  595. if((*modpp)->asic == NULL) {
  596. printk("**WARNING** kmalloc failure in cat_init\n");
  597. continue;
  598. }
  599. memset((*modpp)->asic, 0, sizeof(voyager_asic_t));
  600. (*modpp)->asic->asic_id = VOYAGER_CAT_ID;
  601. (*modpp)->asic->subaddr = VOYAGER_SUBADDR_HI;
  602. (*modpp)->module_addr = i;
  603. (*modpp)->scan_path_connected = 0;
  604. if(i == VOYAGER_PSI) {
  605. /* Exception leg for modules with no EEPROM */
  606. printk("Module \"%s\"\n", cat_module_name(i));
  607. continue;
  608. }
  609. CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
  610. outb(VOYAGER_CAT_RUN, CAT_CMD);
  611. cat_disconnect(*modpp, (*modpp)->asic);
  612. if(cat_subread(*modpp, (*modpp)->asic,
  613. VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
  614. &eprom_size)) {
  615. printk("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n", i);
  616. outb(VOYAGER_CAT_END, CAT_CMD);
  617. continue;
  618. }
  619. if(eprom_size > sizeof(eprom_buf)) {
  620. printk("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x. Need %d\n", i, eprom_size);
  621. outb(VOYAGER_CAT_END, CAT_CMD);
  622. continue;
  623. }
  624. outb(VOYAGER_CAT_END, CAT_CMD);
  625. outb(VOYAGER_CAT_RUN, CAT_CMD);
  626. CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i, eprom_size));
  627. if(cat_subread(*modpp, (*modpp)->asic, 0,
  628. eprom_size, eprom_buf)) {
  629. outb(VOYAGER_CAT_END, CAT_CMD);
  630. continue;
  631. }
  632. outb(VOYAGER_CAT_END, CAT_CMD);
  633. printk("Module \"%s\", version 0x%x, tracer 0x%x, asics %d\n",
  634. cat_module_name(i), eprom_hdr->version_id,
  635. *((__u32 *)eprom_hdr->tracer), eprom_hdr->num_asics);
  636. (*modpp)->ee_size = eprom_hdr->ee_size;
  637. (*modpp)->num_asics = eprom_hdr->num_asics;
  638. asicpp = &((*modpp)->asic);
  639. sp_offset = eprom_hdr->scan_path_offset;
  640. /* All we really care about are the Quad cards. We
  641. * identify them because they are in a processor slot
  642. * and have only four asics */
  643. if((i < 0x10 || (i>=0x14 && i < 0x1c) || i>0x1f)) {
  644. modpp = &((*modpp)->next);
  645. continue;
  646. }
  647. /* Now we know it's in a processor slot, does it have
  648. * a quad baseboard submodule */
  649. outb(VOYAGER_CAT_RUN, CAT_CMD);
  650. cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODPRESENT,
  651. &num_submodules);
  652. /* lowest two bits, active low */
  653. num_submodules = ~(0xfc | num_submodules);
  654. CDEBUG(("VOYAGER CAT: %d submodules present\n", num_submodules));
  655. if(num_submodules == 0) {
  656. /* fill in the dyadic extended processors */
  657. __u8 cpu = i & 0x07;
  658. printk("Module \"%s\": Dyadic Processor Card\n",
  659. cat_module_name(i));
  660. voyager_extended_vic_processors |= (1<<cpu);
  661. cpu += 4;
  662. voyager_extended_vic_processors |= (1<<cpu);
  663. outb(VOYAGER_CAT_END, CAT_CMD);
  664. continue;
  665. }
  666. /* now we want to read the asics on the first submodule,
  667. * which should be the quad base board */
  668. cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, &val);
  669. CDEBUG(("cat_init: SUBMODSELECT value = 0x%x\n", val));
  670. val = (val & 0x7c) | VOYAGER_QUAD_BASEBOARD;
  671. cat_write(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, val);
  672. outb(VOYAGER_CAT_END, CAT_CMD);
  673. CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
  674. outb(VOYAGER_CAT_RUN, CAT_CMD);
  675. cat_disconnect(*modpp, (*modpp)->asic);
  676. if(cat_subread(*modpp, (*modpp)->asic,
  677. VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
  678. &eprom_size)) {
  679. printk("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n", i);
  680. outb(VOYAGER_CAT_END, CAT_CMD);
  681. continue;
  682. }
  683. if(eprom_size > sizeof(eprom_buf)) {
  684. printk("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x. Need %d\n", i, eprom_size);
  685. outb(VOYAGER_CAT_END, CAT_CMD);
  686. continue;
  687. }
  688. outb(VOYAGER_CAT_END, CAT_CMD);
  689. outb(VOYAGER_CAT_RUN, CAT_CMD);
  690. CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i, eprom_size));
  691. if(cat_subread(*modpp, (*modpp)->asic, 0,
  692. eprom_size, eprom_buf)) {
  693. outb(VOYAGER_CAT_END, CAT_CMD);
  694. continue;
  695. }
  696. outb(VOYAGER_CAT_END, CAT_CMD);
  697. /* Now do everything for the QBB submodule 1 */
  698. (*modpp)->ee_size = eprom_hdr->ee_size;
  699. (*modpp)->num_asics = eprom_hdr->num_asics;
  700. asicpp = &((*modpp)->asic);
  701. sp_offset = eprom_hdr->scan_path_offset;
  702. /* get rid of the dummy CAT asic and read the real one */
  703. kfree((*modpp)->asic);
  704. for(asic=0; asic < (*modpp)->num_asics; asic++) {
  705. int j;
  706. voyager_asic_t *asicp = *asicpp
  707. = kmalloc(sizeof(voyager_asic_t), GFP_KERNEL); /*&voyager_asic_storage[asic_count++];*/
  708. voyager_sp_table_t *sp_table;
  709. voyager_at_t *asic_table;
  710. voyager_jtt_t *jtag_table;
  711. if(asicp == NULL) {
  712. printk("**WARNING** kmalloc failure in cat_init\n");
  713. continue;
  714. }
  715. memset(asicp, 0, sizeof(voyager_asic_t));
  716. asicpp = &(asicp->next);
  717. asicp->asic_location = asic;
  718. sp_table = (voyager_sp_table_t *)(eprom_buf + sp_offset);
  719. asicp->asic_id = sp_table->asic_id;
  720. asic_table = (voyager_at_t *)(eprom_buf + sp_table->asic_data_offset);
  721. for(j=0; j<4; j++)
  722. asicp->jtag_id[j] = asic_table->jtag_id[j];
  723. jtag_table = (voyager_jtt_t *)(eprom_buf + asic_table->jtag_offset);
  724. asicp->ireg_length = jtag_table->ireg_len;
  725. asicp->bit_location = (*modpp)->inst_bits;
  726. (*modpp)->inst_bits += asicp->ireg_length;
  727. if(asicp->ireg_length > (*modpp)->largest_reg)
  728. (*modpp)->largest_reg = asicp->ireg_length;
  729. if (asicp->ireg_length < (*modpp)->smallest_reg ||
  730. (*modpp)->smallest_reg == 0)
  731. (*modpp)->smallest_reg = asicp->ireg_length;
  732. CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n",
  733. asicp->asic_id, asicp->ireg_length,
  734. asicp->bit_location));
  735. if(asicp->asic_id == VOYAGER_QUAD_QABC) {
  736. CDEBUG(("VOYAGER CAT: QABC ASIC found\n"));
  737. qabc_asic = asicp;
  738. }
  739. sp_offset += sizeof(voyager_sp_table_t);
  740. }
  741. CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n",
  742. (*modpp)->inst_bits, (*modpp)->largest_reg,
  743. (*modpp)->smallest_reg));
  744. /* OK, now we have the QUAD ASICs set up, use them.
  745. * we need to:
  746. *
  747. * 1. Find the Memory area for the Quad CPIs.
  748. * 2. Find the Extended VIC processor
  749. * 3. Configure a second extended VIC processor (This
  750. * cannot be done for the 51xx.
  751. * */
  752. outb(VOYAGER_CAT_RUN, CAT_CMD);
  753. cat_connect(*modpp, (*modpp)->asic);
  754. CDEBUG(("CAT CONNECTED!!\n"));
  755. cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data);
  756. qic_addr = qabc_data[5] << 8;
  757. qic_addr = (qic_addr | qabc_data[6]) << 8;
  758. qic_addr = (qic_addr | qabc_data[7]) << 8;
  759. printk("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n",
  760. cat_module_name(i), qic_addr, qabc_data[8]);
  761. #if 0 /* plumbing fails---FIXME */
  762. if((qabc_data[8] & 0xf0) == 0) {
  763. /* FIXME: 32 way 8 CPU slot monster cannot be
  764. * plumbed this way---need to check for it */
  765. printk("Plumbing second Extended Quad Processor\n");
  766. /* second VIC line hardwired to Quad CPU 1 */
  767. qabc_data[8] |= 0x20;
  768. cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
  769. #ifdef VOYAGER_CAT_DEBUG
  770. /* verify plumbing */
  771. cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
  772. if((qabc_data[8] & 0xf0) == 0) {
  773. CDEBUG(("PLUMBING FAILED: 0x%x\n", qabc_data[8]));
  774. }
  775. #endif
  776. }
  777. #endif
  778. {
  779. struct resource *res = kmalloc(sizeof(struct resource),GFP_KERNEL);
  780. memset(res, 0, sizeof(struct resource));
  781. res->name = kmalloc(128, GFP_KERNEL);
  782. sprintf((char *)res->name, "Voyager %s Quad CPI", cat_module_name(i));
  783. res->start = qic_addr;
  784. res->end = qic_addr + 0x3ff;
  785. request_resource(&iomem_resource, res);
  786. }
  787. qic_addr = (unsigned long)ioremap(qic_addr, 0x400);
  788. for(j = 0; j < 4; j++) {
  789. __u8 cpu;
  790. if(voyager_8slot) {
  791. /* 8 slot has a different mapping,
  792. * each slot has only one vic line, so
  793. * 1 cpu in each slot must be < 8 */
  794. cpu = (i & 0x07) + j*8;
  795. } else {
  796. cpu = (i & 0x03) + j*4;
  797. }
  798. if( (qabc_data[8] & (1<<j))) {
  799. voyager_extended_vic_processors |= (1<<cpu);
  800. }
  801. if(qabc_data[8] & (1<<(j+4)) ) {
  802. /* Second SET register plumbed: Quad
  803. * card has two VIC connected CPUs.
  804. * Secondary cannot be booted as a VIC
  805. * CPU */
  806. voyager_extended_vic_processors |= (1<<cpu);
  807. voyager_allowed_boot_processors &= (~(1<<cpu));
  808. }
  809. voyager_quad_processors |= (1<<cpu);
  810. voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *)
  811. (qic_addr+(j<<8));
  812. CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu,
  813. (unsigned long)voyager_quad_cpi_addr[cpu]));
  814. }
  815. outb(VOYAGER_CAT_END, CAT_CMD);
  816. *asicpp = NULL;
  817. modpp = &((*modpp)->next);
  818. }
  819. *modpp = NULL;
  820. printk("CAT Bus Initialisation finished: extended procs 0x%x, quad procs 0x%x, allowed vic boot = 0x%x\n", voyager_extended_vic_processors, voyager_quad_processors, voyager_allowed_boot_processors);
  821. request_resource(&ioport_resource, &vic_res);
  822. if(voyager_quad_processors)
  823. request_resource(&ioport_resource, &qic_res);
  824. /* set up the front power switch */
  825. }
  826. int
  827. voyager_cat_readb(__u8 module, __u8 asic, int reg)
  828. {
  829. return 0;
  830. }
  831. static int
  832. cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp)
  833. {
  834. __u8 val;
  835. int err = 0;
  836. if(!modp->scan_path_connected)
  837. return 0;
  838. if(asicp->asic_id != VOYAGER_CAT_ID) {
  839. CDEBUG(("cat_disconnect: ASIC is not CAT\n"));
  840. return 1;
  841. }
  842. err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
  843. if(err) {
  844. CDEBUG(("cat_disconnect: failed to read SCANPATH\n"));
  845. return err;
  846. }
  847. val &= VOYAGER_DISCONNECT_ASIC;
  848. err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
  849. if(err) {
  850. CDEBUG(("cat_disconnect: failed to write SCANPATH\n"));
  851. return err;
  852. }
  853. outb(VOYAGER_CAT_END, CAT_CMD);
  854. outb(VOYAGER_CAT_RUN, CAT_CMD);
  855. modp->scan_path_connected = 0;
  856. return 0;
  857. }
  858. static int
  859. cat_connect(voyager_module_t *modp, voyager_asic_t *asicp)
  860. {
  861. __u8 val;
  862. int err = 0;
  863. if(modp->scan_path_connected)
  864. return 0;
  865. if(asicp->asic_id != VOYAGER_CAT_ID) {
  866. CDEBUG(("cat_connect: ASIC is not CAT\n"));
  867. return 1;
  868. }
  869. err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
  870. if(err) {
  871. CDEBUG(("cat_connect: failed to read SCANPATH\n"));
  872. return err;
  873. }
  874. val |= VOYAGER_CONNECT_ASIC;
  875. err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
  876. if(err) {
  877. CDEBUG(("cat_connect: failed to write SCANPATH\n"));
  878. return err;
  879. }
  880. outb(VOYAGER_CAT_END, CAT_CMD);
  881. outb(VOYAGER_CAT_RUN, CAT_CMD);
  882. modp->scan_path_connected = 1;
  883. return 0;
  884. }
  885. void
  886. voyager_cat_power_off(void)
  887. {
  888. /* Power the machine off by writing to the PSI over the CAT
  889. * bus */
  890. __u8 data;
  891. voyager_module_t psi = { 0 };
  892. voyager_asic_t psi_asic = { 0 };
  893. psi.asic = &psi_asic;
  894. psi.asic->asic_id = VOYAGER_CAT_ID;
  895. psi.asic->subaddr = VOYAGER_SUBADDR_HI;
  896. psi.module_addr = VOYAGER_PSI;
  897. psi.scan_path_connected = 0;
  898. outb(VOYAGER_CAT_END, CAT_CMD);
  899. /* Connect the PSI to the CAT Bus */
  900. outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
  901. outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
  902. outb(VOYAGER_CAT_RUN, CAT_CMD);
  903. cat_disconnect(&psi, &psi_asic);
  904. /* Read the status */
  905. cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
  906. outb(VOYAGER_CAT_END, CAT_CMD);
  907. CDEBUG(("PSI STATUS 0x%x\n", data));
  908. /* These two writes are power off prep and perform */
  909. data = PSI_CLEAR;
  910. outb(VOYAGER_CAT_RUN, CAT_CMD);
  911. cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
  912. outb(VOYAGER_CAT_END, CAT_CMD);
  913. data = PSI_POWER_DOWN;
  914. outb(VOYAGER_CAT_RUN, CAT_CMD);
  915. cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
  916. outb(VOYAGER_CAT_END, CAT_CMD);
  917. }
  918. struct voyager_status voyager_status = { 0 };
  919. void
  920. voyager_cat_psi(__u8 cmd, __u16 reg, __u8 *data)
  921. {
  922. voyager_module_t psi = { 0 };
  923. voyager_asic_t psi_asic = { 0 };
  924. psi.asic = &psi_asic;
  925. psi.asic->asic_id = VOYAGER_CAT_ID;
  926. psi.asic->subaddr = VOYAGER_SUBADDR_HI;
  927. psi.module_addr = VOYAGER_PSI;
  928. psi.scan_path_connected = 0;
  929. outb(VOYAGER_CAT_END, CAT_CMD);
  930. /* Connect the PSI to the CAT Bus */
  931. outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
  932. outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
  933. outb(VOYAGER_CAT_RUN, CAT_CMD);
  934. cat_disconnect(&psi, &psi_asic);
  935. switch(cmd) {
  936. case VOYAGER_PSI_READ:
  937. cat_read(&psi, &psi_asic, reg, data);
  938. break;
  939. case VOYAGER_PSI_WRITE:
  940. cat_write(&psi, &psi_asic, reg, *data);
  941. break;
  942. case VOYAGER_PSI_SUBREAD:
  943. cat_subread(&psi, &psi_asic, reg, 1, data);
  944. break;
  945. case VOYAGER_PSI_SUBWRITE:
  946. cat_subwrite(&psi, &psi_asic, reg, 1, data);
  947. break;
  948. default:
  949. printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd);
  950. break;
  951. }
  952. outb(VOYAGER_CAT_END, CAT_CMD);
  953. }
  954. void
  955. voyager_cat_do_common_interrupt(void)
  956. {
  957. /* This is caused either by a memory parity error or something
  958. * in the PSI */
  959. __u8 data;
  960. voyager_module_t psi = { 0 };
  961. voyager_asic_t psi_asic = { 0 };
  962. struct voyager_psi psi_reg;
  963. int i;
  964. re_read:
  965. psi.asic = &psi_asic;
  966. psi.asic->asic_id = VOYAGER_CAT_ID;
  967. psi.asic->subaddr = VOYAGER_SUBADDR_HI;
  968. psi.module_addr = VOYAGER_PSI;
  969. psi.scan_path_connected = 0;
  970. outb(VOYAGER_CAT_END, CAT_CMD);
  971. /* Connect the PSI to the CAT Bus */
  972. outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
  973. outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
  974. outb(VOYAGER_CAT_RUN, CAT_CMD);
  975. cat_disconnect(&psi, &psi_asic);
  976. /* Read the status. NOTE: Need to read *all* the PSI regs here
  977. * otherwise the cmn int will be reasserted */
  978. for(i = 0; i < sizeof(psi_reg.regs); i++) {
  979. cat_read(&psi, &psi_asic, i, &((__u8 *)&psi_reg.regs)[i]);
  980. }
  981. outb(VOYAGER_CAT_END, CAT_CMD);
  982. if((psi_reg.regs.checkbit & 0x02) == 0) {
  983. psi_reg.regs.checkbit |= 0x02;
  984. cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit);
  985. printk("VOYAGER RE-READ PSI\n");
  986. goto re_read;
  987. }
  988. outb(VOYAGER_CAT_RUN, CAT_CMD);
  989. for(i = 0; i < sizeof(psi_reg.subregs); i++) {
  990. /* This looks strange, but the PSI doesn't do auto increment
  991. * correctly */
  992. cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i,
  993. 1, &((__u8 *)&psi_reg.subregs)[i]);
  994. }
  995. outb(VOYAGER_CAT_END, CAT_CMD);
  996. #ifdef VOYAGER_CAT_DEBUG
  997. printk("VOYAGER PSI: ");
  998. for(i=0; i<sizeof(psi_reg.regs); i++)
  999. printk("%02x ", ((__u8 *)&psi_reg.regs)[i]);
  1000. printk("\n ");
  1001. for(i=0; i<sizeof(psi_reg.subregs); i++)
  1002. printk("%02x ", ((__u8 *)&psi_reg.subregs)[i]);
  1003. printk("\n");
  1004. #endif
  1005. if(psi_reg.regs.intstatus & PSI_MON) {
  1006. /* switch off or power fail */
  1007. if(psi_reg.subregs.supply & PSI_SWITCH_OFF) {
  1008. if(voyager_status.switch_off) {
  1009. printk(KERN_ERR "Voyager front panel switch turned off again---Immediate power off!\n");
  1010. voyager_cat_power_off();
  1011. /* not reached */
  1012. } else {
  1013. printk(KERN_ERR "Voyager front panel switch turned off\n");
  1014. voyager_status.switch_off = 1;
  1015. voyager_status.request_from_kernel = 1;
  1016. up(&kvoyagerd_sem);
  1017. }
  1018. /* Tell the hardware we're taking care of the
  1019. * shutdown, otherwise it will power the box off
  1020. * within 3 seconds of the switch being pressed and,
  1021. * which is much more important to us, continue to
  1022. * assert the common interrupt */
  1023. data = PSI_CLR_SWITCH_OFF;
  1024. outb(VOYAGER_CAT_RUN, CAT_CMD);
  1025. cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG,
  1026. 1, &data);
  1027. outb(VOYAGER_CAT_END, CAT_CMD);
  1028. } else {
  1029. VDEBUG(("Voyager ac fail reg 0x%x\n",
  1030. psi_reg.subregs.ACfail));
  1031. if((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) {
  1032. /* No further update */
  1033. return;
  1034. }
  1035. #if 0
  1036. /* Don't bother trying to find out who failed.
  1037. * FIXME: This probably makes the code incorrect on
  1038. * anything other than a 345x */
  1039. for(i=0; i< 5; i++) {
  1040. if( psi_reg.subregs.ACfail &(1<<i)) {
  1041. break;
  1042. }
  1043. }
  1044. printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);
  1045. #endif
  1046. /* DON'T do this: it shuts down the AC PSI
  1047. outb(VOYAGER_CAT_RUN, CAT_CMD);
  1048. data = PSI_MASK_MASK | i;
  1049. cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK,
  1050. 1, &data);
  1051. outb(VOYAGER_CAT_END, CAT_CMD);
  1052. */
  1053. printk(KERN_ERR "Voyager AC power failure\n");
  1054. outb(VOYAGER_CAT_RUN, CAT_CMD);
  1055. data = PSI_COLD_START;
  1056. cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG,
  1057. 1, &data);
  1058. outb(VOYAGER_CAT_END, CAT_CMD);
  1059. voyager_status.power_fail = 1;
  1060. voyager_status.request_from_kernel = 1;
  1061. up(&kvoyagerd_sem);
  1062. }
  1063. } else if(psi_reg.regs.intstatus & PSI_FAULT) {
  1064. /* Major fault! */
  1065. printk(KERN_ERR "Voyager PSI Detected major fault, immediate power off!\n");
  1066. voyager_cat_power_off();
  1067. /* not reached */
  1068. } else if(psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM
  1069. | PSI_CURRENT | PSI_DVM
  1070. | PSI_PSCFAULT | PSI_STAT_CHG)) {
  1071. /* other psi fault */
  1072. printk(KERN_WARNING "Voyager PSI status 0x%x\n", data);
  1073. /* clear the PSI fault */
  1074. outb(VOYAGER_CAT_RUN, CAT_CMD);
  1075. cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0);
  1076. outb(VOYAGER_CAT_END, CAT_CMD);
  1077. }
  1078. }