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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Compaq Hot Plug Controller Driver
  3.  *
  4.  * Copyright (c) 1995,2001 Compaq Computer Corporation
  5.  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  6.  * Copyright (c) 2001 IBM Corp.
  7.  *
  8.  * All rights reserved.
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or (at
  13.  * your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful, but
  16.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  18.  * NON INFRINGEMENT.  See the GNU General Public License for more
  19.  * details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  *
  25.  * Send feedback to <greg@kroah.com>
  26.  *
  27.  */
  28. #include <linux/config.h>
  29. #include <linux/module.h>
  30. #include <linux/kernel.h>
  31. #include <linux/types.h>
  32. #include <linux/proc_fs.h>
  33. #include <linux/miscdevice.h>
  34. #include <linux/slab.h>
  35. #include <linux/pci.h>
  36. #include <linux/init.h>
  37. #include <asm/uaccess.h>
  38. #include "cpqphp.h"
  39. #include "cpqphp_nvram.h"
  40. #define ROM_INT15_PHY_ADDR 0x0FF859
  41. #define READ_EV 0xD8A4
  42. #define WRITE_EV 0xD8A5
  43. struct register_foo {
  44. union {
  45. unsigned long lword; /* eax */
  46. unsigned short word; /* ax */
  47. struct {
  48. unsigned char low; /* al */
  49. unsigned char high; /* ah */
  50. } byte;
  51. } data;
  52. unsigned char opcode; /* see below */
  53. unsigned long length; /* if the reg. is a pointer, how much data */
  54. } __attribute__ ((packed));
  55. struct all_reg {
  56. struct register_foo eax_reg;
  57. struct register_foo ebx_reg;
  58. struct register_foo ecx_reg;
  59. struct register_foo edx_reg;
  60. struct register_foo edi_reg;
  61. struct register_foo esi_reg;
  62. struct register_foo eflags_reg;
  63. } __attribute__ ((packed));
  64. struct ev_hrt_header {
  65. u8 Version;
  66. u8 num_of_ctrl;
  67. u8 next;
  68. };
  69. struct ev_hrt_ctrl {
  70. u8 bus;
  71. u8 device;
  72. u8 function;
  73. u8 mem_avail;
  74. u8 p_mem_avail;
  75. u8 io_avail;
  76. u8 bus_avail;
  77. u8 next;
  78. };
  79. static u8 evbuffer_init;
  80. static u8 evbuffer_length;
  81. static u8 evbuffer[1024];
  82. static void *compaq_int15_entry_point;
  83. static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */
  84. /* This is a series of function that deals with
  85.    setting & getting the hotplug resource table in some environment variable.
  86. */
  87. /*
  88.  * We really shouldn't be doing this unless there is a _very_ good reason to!!!
  89.  * greg k-h
  90.  */
  91. static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail)
  92. {
  93. u8 **tByte;
  94. if ((*used + 1) > *avail)
  95. return(1);
  96. *((u8*)*p_buffer) = value;
  97. tByte = (u8**)p_buffer;
  98. (*tByte)++;
  99. *used+=1;
  100. return(0);
  101. }
  102. static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail)
  103. {
  104. if ((*used + 4) > *avail)
  105. return(1);
  106. **p_buffer = value;
  107. (*p_buffer)++;
  108. *used+=4;
  109. return(0);
  110. }
  111. /*
  112.  * check_for_compaq_ROM
  113.  *
  114.  * this routine verifies that the ROM OEM string is 'COMPAQ'
  115.  *
  116.  * returns 0 for non-Compaq ROM, 1 for Compaq ROM
  117.  */
  118. static int check_for_compaq_ROM (void *rom_start)
  119. {
  120. u8 temp1, temp2, temp3, temp4, temp5, temp6;
  121. int result = 0;
  122. temp1 = readb(rom_start + 0xffea + 0);
  123. temp2 = readb(rom_start + 0xffea + 1);
  124. temp3 = readb(rom_start + 0xffea + 2);
  125. temp4 = readb(rom_start + 0xffea + 3);
  126. temp5 = readb(rom_start + 0xffea + 4);
  127. temp6 = readb(rom_start + 0xffea + 5);
  128. if ((temp1 == 'C') &&
  129.     (temp2 == 'O') &&
  130.     (temp3 == 'M') &&
  131.     (temp4 == 'P') &&
  132.     (temp5 == 'A') &&
  133.     (temp6 == 'Q')) {
  134. result = 1;
  135. }
  136. dbg (__FUNCTION__" - returned %dn", result);
  137. return result;
  138. }
  139. static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
  140. {
  141. unsigned long flags;
  142. int op = operation;
  143. int ret_val;
  144. if (!compaq_int15_entry_point)
  145. return -ENODEV;
  146. spin_lock_irqsave(&int15_lock, flags);
  147. __asm__ (
  148. "xorl   %%ebx,%%ebx
  149. xorl    %%edx,%%edx
  150. pushf
  151. push    %%cs
  152. cli
  153. call    *%6"
  154. : "=c" (*buf_size), "=a" (ret_val)
  155. : "a" (op), "c" (*buf_size), "S" (ev_name),
  156. "D" (buffer), "m" (compaq_int15_entry_point)
  157. : "%ebx", "%edx");
  158. spin_unlock_irqrestore(&int15_lock, flags);
  159. return((ret_val & 0xFF00) >> 8);
  160. }
  161. /*
  162.  * load_HRT
  163.  *
  164.  * Read the hot plug Resource Table from NVRAM
  165.  */
  166. static int load_HRT (void *rom_start)
  167. {
  168. u32 available;
  169. u32 temp_dword;
  170. u8 temp_byte = 0xFF;
  171. u32 rc;
  172. if (!check_for_compaq_ROM(rom_start)) {
  173. return -ENODEV;
  174. }
  175. available = 1024;
  176. // Now load the EV
  177. temp_dword = available;
  178. rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
  179. evbuffer_length = temp_dword;
  180. // We're maintaining the resource lists so write FF to invalidate old info
  181. temp_dword = 1;
  182. rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
  183. return rc;
  184. }
  185. /*
  186.  * store_HRT
  187.  *
  188.  * Save the hot plug Resource Table in NVRAM
  189.  */
  190. static u32 store_HRT (void *rom_start)
  191. {
  192. u32 *buffer;
  193. u32 *pFill;
  194. u32 usedbytes;
  195. u32 available;
  196. u32 temp_dword;
  197. u32 rc;
  198. u8 loop;
  199. u8 numCtrl = 0;
  200. struct controller *ctrl;
  201. struct pci_resource *resNode;
  202. struct ev_hrt_header *p_EV_header;
  203. struct ev_hrt_ctrl *p_ev_ctrl;
  204. available = 1024;
  205. if (!check_for_compaq_ROM(rom_start)) {
  206. return(1);
  207. }
  208. buffer = (u32*) evbuffer;
  209. if (!buffer)
  210. return(1);
  211. pFill = buffer;
  212. usedbytes = 0;
  213. p_EV_header = (struct ev_hrt_header *) pFill;
  214. ctrl = cpqhp_ctrl_list;
  215. // The revision of this structure
  216. rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
  217. if (rc)
  218. return(rc);
  219. // The number of controllers
  220. rc = add_byte( &pFill, 1, &usedbytes, &available);
  221. if (rc)
  222. return(rc);
  223. while (ctrl) {
  224. p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
  225. numCtrl++;
  226. // The bus number
  227. rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
  228. if (rc)
  229. return(rc);
  230. // The device Number
  231. rc = add_byte( &pFill, ctrl->device, &usedbytes, &available);
  232. if (rc)
  233. return(rc);
  234. // The function Number
  235. rc = add_byte( &pFill, ctrl->function, &usedbytes, &available);
  236. if (rc)
  237. return(rc);
  238. // Skip the number of available entries
  239. rc = add_dword( &pFill, 0, &usedbytes, &available);
  240. if (rc)
  241. return(rc);
  242. // Figure out memory Available
  243. resNode = ctrl->mem_head;
  244. loop = 0;
  245. while (resNode) {
  246. loop ++;
  247. // base
  248. rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
  249. if (rc)
  250. return(rc);
  251. // length
  252. rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
  253. if (rc)
  254. return(rc);
  255. resNode = resNode->next;
  256. }
  257. // Fill in the number of entries
  258. p_ev_ctrl->mem_avail = loop;
  259. // Figure out prefetchable memory Available
  260. resNode = ctrl->p_mem_head;
  261. loop = 0;
  262. while (resNode) {
  263. loop ++;
  264. // base
  265. rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
  266. if (rc)
  267. return(rc);
  268. // length
  269. rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
  270. if (rc)
  271. return(rc);
  272. resNode = resNode->next;
  273. }
  274. // Fill in the number of entries
  275. p_ev_ctrl->p_mem_avail = loop;
  276. // Figure out IO Available
  277. resNode = ctrl->io_head;
  278. loop = 0;
  279. while (resNode) {
  280. loop ++;
  281. // base
  282. rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
  283. if (rc)
  284. return(rc);
  285. // length
  286. rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
  287. if (rc)
  288. return(rc);
  289. resNode = resNode->next;
  290. }
  291. // Fill in the number of entries
  292. p_ev_ctrl->io_avail = loop;
  293. // Figure out bus Available
  294. resNode = ctrl->bus_head;
  295. loop = 0;
  296. while (resNode) {
  297. loop ++;
  298. // base
  299. rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
  300. if (rc)
  301. return(rc);
  302. // length
  303. rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
  304. if (rc)
  305. return(rc);
  306. resNode = resNode->next;
  307. }
  308. // Fill in the number of entries
  309. p_ev_ctrl->bus_avail = loop;
  310. ctrl = ctrl->next;
  311. }
  312. p_EV_header->num_of_ctrl = numCtrl;
  313. // Now store the EV
  314. temp_dword = usedbytes;
  315. rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword);
  316. dbg("usedbytes = 0x%x, length = 0x%xn", usedbytes, temp_dword);
  317. evbuffer_length = temp_dword;
  318. if (rc) {
  319. err(msg_unable_to_save);
  320. return(1);
  321. }
  322. return(0);
  323. }
  324. void compaq_nvram_init (void *rom_start)
  325. {
  326. if (rom_start) {
  327. compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
  328. }
  329. dbg("int15 entry  = %pn", compaq_int15_entry_point);
  330. /* initialize our int15 lock */
  331. spin_lock_init(&int15_lock);
  332. }
  333. int compaq_nvram_load (void *rom_start, struct controller *ctrl)
  334. {
  335. u8 bus, device, function;
  336. u8 nummem, numpmem, numio, numbus;
  337. u32 rc;
  338. u8 *p_byte;
  339. struct pci_resource *mem_node;
  340. struct pci_resource *p_mem_node;
  341. struct pci_resource *io_node;
  342. struct pci_resource *bus_node;
  343. struct ev_hrt_ctrl *p_ev_ctrl;
  344. struct ev_hrt_header *p_EV_header;
  345. if (!evbuffer_init) {
  346. // Read the resource list information in from NVRAM
  347. if (load_HRT(rom_start))
  348. memset (evbuffer, 0, 1024);
  349. evbuffer_init = 1;
  350. }
  351. // If we saved information in NVRAM, use it now
  352. p_EV_header = (struct ev_hrt_header *) evbuffer;
  353. // The following code is for systems where version 1.0 of this
  354. // driver has been loaded, but doesn't support the hardware.
  355. // In that case, the driver would incorrectly store something
  356. // in NVRAM.
  357. if ((p_EV_header->Version == 2) ||
  358.     ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
  359. p_byte = &(p_EV_header->next);
  360. p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
  361. p_byte += 3;
  362. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  363. return(2);
  364. bus = p_ev_ctrl->bus;
  365. device = p_ev_ctrl->device;
  366. function = p_ev_ctrl->function;
  367. while ((bus != ctrl->bus) || (device != ctrl->device)
  368.        || (function != ctrl->function)) {
  369. nummem = p_ev_ctrl->mem_avail;
  370. numpmem = p_ev_ctrl->p_mem_avail;
  371. numio = p_ev_ctrl->io_avail;
  372. numbus = p_ev_ctrl->bus_avail;
  373. p_byte += 4;
  374. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  375. return(2);
  376. // Skip forward to the next entry
  377. p_byte += (nummem + numpmem + numio + numbus) * 8;
  378. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  379. return(2);
  380. p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
  381. p_byte += 3;
  382. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  383. return(2);
  384. bus = p_ev_ctrl->bus;
  385. device = p_ev_ctrl->device;
  386. function = p_ev_ctrl->function;
  387. }
  388. nummem = p_ev_ctrl->mem_avail;
  389. numpmem = p_ev_ctrl->p_mem_avail;
  390. numio = p_ev_ctrl->io_avail;
  391. numbus = p_ev_ctrl->bus_avail;
  392. p_byte += 4;
  393. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  394. return(2);
  395. while (nummem--) {
  396. mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  397. if (!mem_node)
  398. break;
  399. mem_node->base = *(u32*)p_byte;
  400. dbg("mem base = %8.8xn",mem_node->base);
  401. p_byte += 4;
  402. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  403. return(2);
  404. mem_node->length = *(u32*)p_byte;
  405. dbg("mem length = %8.8xn",mem_node->length);
  406. p_byte += 4;
  407. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  408. return(2);
  409. mem_node->next = ctrl->mem_head;
  410. ctrl->mem_head = mem_node;
  411. }
  412. while (numpmem--) {
  413. p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  414. if (!p_mem_node)
  415. break;
  416. p_mem_node->base = *(u32*)p_byte;
  417. dbg("pre-mem base = %8.8xn",p_mem_node->base);
  418. p_byte += 4;
  419. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  420. return(2);
  421. p_mem_node->length = *(u32*)p_byte;
  422. dbg("pre-mem length = %8.8xn",p_mem_node->length);
  423. p_byte += 4;
  424. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  425. return(2);
  426. p_mem_node->next = ctrl->p_mem_head;
  427. ctrl->p_mem_head = p_mem_node;
  428. }
  429. while (numio--) {
  430. io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  431. if (!io_node)
  432. break;
  433. io_node->base = *(u32*)p_byte;
  434. dbg("io base = %8.8xn",io_node->base);
  435. p_byte += 4;
  436. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  437. return(2);
  438. io_node->length = *(u32*)p_byte;
  439. dbg("io length = %8.8xn",io_node->length);
  440. p_byte += 4;
  441. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  442. return(2);
  443. io_node->next = ctrl->io_head;
  444. ctrl->io_head = io_node;
  445. }
  446. while (numbus--) {
  447. bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  448. if (!bus_node)
  449. break;
  450. bus_node->base = *(u32*)p_byte;
  451. p_byte += 4;
  452. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  453. return(2);
  454. bus_node->length = *(u32*)p_byte;
  455. p_byte += 4;
  456. if (p_byte > ((u8*)p_EV_header + evbuffer_length))
  457. return(2);
  458. bus_node->next = ctrl->bus_head;
  459. ctrl->bus_head = bus_node;
  460. }
  461. // If all of the following fail, we don't have any resources for
  462. // hot plug add
  463. rc = 1;
  464. rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
  465. rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
  466. rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
  467. rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
  468. if (rc) {
  469. return(rc);
  470. }
  471. } else {
  472. if ((evbuffer[0] != 0) && (!ctrl->push_flag)) {
  473. return(1);
  474. }
  475. }
  476. return 0;
  477. }
  478. int compaq_nvram_store (void *rom_start)
  479. {
  480. int rc = 1;
  481. if (rom_start == NULL)
  482. return -ENODEV;
  483. if (evbuffer_init) {
  484. rc = store_HRT(rom_start);
  485. if (rc) {
  486. err(msg_unable_to_save);
  487. }
  488. }
  489. return rc;
  490. }