acpiphp_res.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /*
  2. * ACPI PCI HotPlug Utility functions
  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. * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
  8. * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
  9. * Copyright (C) 2002 NEC Corporation
  10. *
  11. * All rights reserved.
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 2 of the License, or (at
  16. * your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful, but
  19. * WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  21. * NON INFRINGEMENT. See the GNU General Public License for more
  22. * details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27. *
  28. * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
  29. *
  30. */
  31. #include <linux/init.h>
  32. #include <linux/module.h>
  33. #include <linux/kernel.h>
  34. #include <linux/types.h>
  35. #include <linux/proc_fs.h>
  36. #include <linux/sysctl.h>
  37. #include <linux/pci.h>
  38. #include <linux/smp.h>
  39. #include <linux/smp_lock.h>
  40. #include <linux/string.h>
  41. #include <linux/mm.h>
  42. #include <linux/errno.h>
  43. #include <linux/ioport.h>
  44. #include <linux/slab.h>
  45. #include <linux/interrupt.h>
  46. #include <linux/timer.h>
  47. #include <linux/ioctl.h>
  48. #include <linux/fcntl.h>
  49. #include <linux/list.h>
  50. #include "pci_hotplug.h"
  51. #include "acpiphp.h"
  52. #define MY_NAME "acpiphp_res"
  53. /*
  54. * sort_by_size - sort nodes by their length, smallest first
  55. */
  56. static int sort_by_size(struct pci_resource **head)
  57. {
  58. struct pci_resource *current_res;
  59. struct pci_resource *next_res;
  60. int out_of_order = 1;
  61. if (!(*head))
  62. return 1;
  63. if (!((*head)->next))
  64. return 0;
  65. while (out_of_order) {
  66. out_of_order = 0;
  67. /* Special case for swapping list head */
  68. if (((*head)->next) &&
  69. ((*head)->length > (*head)->next->length)) {
  70. out_of_order++;
  71. current_res = *head;
  72. *head = (*head)->next;
  73. current_res->next = (*head)->next;
  74. (*head)->next = current_res;
  75. }
  76. current_res = *head;
  77. while (current_res->next && current_res->next->next) {
  78. if (current_res->next->length > current_res->next->next->length) {
  79. out_of_order++;
  80. next_res = current_res->next;
  81. current_res->next = current_res->next->next;
  82. current_res = current_res->next;
  83. next_res->next = current_res->next;
  84. current_res->next = next_res;
  85. } else
  86. current_res = current_res->next;
  87. }
  88. } /* End of out_of_order loop */
  89. return 0;
  90. }
  91. #if 0
  92. /*
  93. * sort_by_max_size - sort nodes by their length, largest first
  94. */
  95. static int sort_by_max_size(struct pci_resource **head)
  96. {
  97. struct pci_resource *current_res;
  98. struct pci_resource *next_res;
  99. int out_of_order = 1;
  100. if (!(*head))
  101. return 1;
  102. if (!((*head)->next))
  103. return 0;
  104. while (out_of_order) {
  105. out_of_order = 0;
  106. /* Special case for swapping list head */
  107. if (((*head)->next) &&
  108. ((*head)->length < (*head)->next->length)) {
  109. out_of_order++;
  110. current_res = *head;
  111. *head = (*head)->next;
  112. current_res->next = (*head)->next;
  113. (*head)->next = current_res;
  114. }
  115. current_res = *head;
  116. while (current_res->next && current_res->next->next) {
  117. if (current_res->next->length < current_res->next->next->length) {
  118. out_of_order++;
  119. next_res = current_res->next;
  120. current_res->next = current_res->next->next;
  121. current_res = current_res->next;
  122. next_res->next = current_res->next;
  123. current_res->next = next_res;
  124. } else
  125. current_res = current_res->next;
  126. }
  127. } /* End of out_of_order loop */
  128. return 0;
  129. }
  130. #endif
  131. /**
  132. * get_io_resource - get resource for I/O ports
  133. *
  134. * this function sorts the resource list by size and then
  135. * returns the first node of "size" length that is not in the
  136. * ISA aliasing window. If it finds a node larger than "size"
  137. * it will split it up.
  138. *
  139. * size must be a power of two.
  140. *
  141. * difference from get_resource is handling of ISA aliasing space.
  142. *
  143. */
  144. struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
  145. {
  146. struct pci_resource *prevnode;
  147. struct pci_resource *node;
  148. struct pci_resource *split_node;
  149. u64 temp_qword;
  150. if (!(*head))
  151. return NULL;
  152. if (acpiphp_resource_sort_and_combine(head))
  153. return NULL;
  154. if (sort_by_size(head))
  155. return NULL;
  156. for (node = *head; node; node = node->next) {
  157. if (node->length < size)
  158. continue;
  159. if (node->base & (size - 1)) {
  160. /* this one isn't base aligned properly
  161. so we'll make a new entry and split it up */
  162. temp_qword = (node->base | (size-1)) + 1;
  163. /* Short circuit if adjusted size is too small */
  164. if ((node->length - (temp_qword - node->base)) < size)
  165. continue;
  166. split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
  167. if (!split_node)
  168. return NULL;
  169. node->base = temp_qword;
  170. node->length -= split_node->length;
  171. /* Put it in the list */
  172. split_node->next = node->next;
  173. node->next = split_node;
  174. } /* End of non-aligned base */
  175. /* Don't need to check if too small since we already did */
  176. if (node->length > size) {
  177. /* this one is longer than we need
  178. so we'll make a new entry and split it up */
  179. split_node = acpiphp_make_resource(node->base + size, node->length - size);
  180. if (!split_node)
  181. return NULL;
  182. node->length = size;
  183. /* Put it in the list */
  184. split_node->next = node->next;
  185. node->next = split_node;
  186. } /* End of too big on top end */
  187. /* For IO make sure it's not in the ISA aliasing space */
  188. if ((node->base & 0x300L) && !(node->base & 0xfffff000))
  189. continue;
  190. /* If we got here, then it is the right size
  191. Now take it out of the list */
  192. if (*head == node) {
  193. *head = node->next;
  194. } else {
  195. prevnode = *head;
  196. while (prevnode->next != node)
  197. prevnode = prevnode->next;
  198. prevnode->next = node->next;
  199. }
  200. node->next = NULL;
  201. /* Stop looping */
  202. break;
  203. }
  204. return node;
  205. }
  206. #if 0
  207. /**
  208. * get_max_resource - get the largest resource
  209. *
  210. * Gets the largest node that is at least "size" big from the
  211. * list pointed to by head. It aligns the node on top and bottom
  212. * to "size" alignment before returning it.
  213. */
  214. static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
  215. {
  216. struct pci_resource *max;
  217. struct pci_resource *temp;
  218. struct pci_resource *split_node;
  219. u64 temp_qword;
  220. if (!(*head))
  221. return NULL;
  222. if (acpiphp_resource_sort_and_combine(head))
  223. return NULL;
  224. if (sort_by_max_size(head))
  225. return NULL;
  226. for (max = *head;max; max = max->next) {
  227. /* If not big enough we could probably just bail,
  228. instead we'll continue to the next. */
  229. if (max->length < size)
  230. continue;
  231. if (max->base & (size - 1)) {
  232. /* this one isn't base aligned properly
  233. so we'll make a new entry and split it up */
  234. temp_qword = (max->base | (size-1)) + 1;
  235. /* Short circuit if adjusted size is too small */
  236. if ((max->length - (temp_qword - max->base)) < size)
  237. continue;
  238. split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
  239. if (!split_node)
  240. return NULL;
  241. max->base = temp_qword;
  242. max->length -= split_node->length;
  243. /* Put it next in the list */
  244. split_node->next = max->next;
  245. max->next = split_node;
  246. }
  247. if ((max->base + max->length) & (size - 1)) {
  248. /* this one isn't end aligned properly at the top
  249. so we'll make a new entry and split it up */
  250. temp_qword = ((max->base + max->length) & ~(size - 1));
  251. split_node = acpiphp_make_resource(temp_qword,
  252. max->length + max->base - temp_qword);
  253. if (!split_node)
  254. return NULL;
  255. max->length -= split_node->length;
  256. /* Put it in the list */
  257. split_node->next = max->next;
  258. max->next = split_node;
  259. }
  260. /* Make sure it didn't shrink too much when we aligned it */
  261. if (max->length < size)
  262. continue;
  263. /* Now take it out of the list */
  264. temp = (struct pci_resource*) *head;
  265. if (temp == max) {
  266. *head = max->next;
  267. } else {
  268. while (temp && temp->next != max) {
  269. temp = temp->next;
  270. }
  271. temp->next = max->next;
  272. }
  273. max->next = NULL;
  274. return max;
  275. }
  276. /* If we get here, we couldn't find one */
  277. return NULL;
  278. }
  279. #endif
  280. /**
  281. * get_resource - get resource (mem, pfmem)
  282. *
  283. * this function sorts the resource list by size and then
  284. * returns the first node of "size" length. If it finds a node
  285. * larger than "size" it will split it up.
  286. *
  287. * size must be a power of two.
  288. *
  289. */
  290. struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
  291. {
  292. struct pci_resource *prevnode;
  293. struct pci_resource *node;
  294. struct pci_resource *split_node;
  295. u64 temp_qword;
  296. if (!(*head))
  297. return NULL;
  298. if (acpiphp_resource_sort_and_combine(head))
  299. return NULL;
  300. if (sort_by_size(head))
  301. return NULL;
  302. for (node = *head; node; node = node->next) {
  303. dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
  304. __FUNCTION__, size, node, (u32)node->base, node->length);
  305. if (node->length < size)
  306. continue;
  307. if (node->base & (size - 1)) {
  308. dbg("%s: not aligned\n", __FUNCTION__);
  309. /* this one isn't base aligned properly
  310. so we'll make a new entry and split it up */
  311. temp_qword = (node->base | (size-1)) + 1;
  312. /* Short circuit if adjusted size is too small */
  313. if ((node->length - (temp_qword - node->base)) < size)
  314. continue;
  315. split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
  316. if (!split_node)
  317. return NULL;
  318. node->base = temp_qword;
  319. node->length -= split_node->length;
  320. /* Put it in the list */
  321. split_node->next = node->next;
  322. node->next = split_node;
  323. } /* End of non-aligned base */
  324. /* Don't need to check if too small since we already did */
  325. if (node->length > size) {
  326. dbg("%s: too big\n", __FUNCTION__);
  327. /* this one is longer than we need
  328. so we'll make a new entry and split it up */
  329. split_node = acpiphp_make_resource(node->base + size, node->length - size);
  330. if (!split_node)
  331. return NULL;
  332. node->length = size;
  333. /* Put it in the list */
  334. split_node->next = node->next;
  335. node->next = split_node;
  336. } /* End of too big on top end */
  337. dbg("%s: got one!!!\n", __FUNCTION__);
  338. /* If we got here, then it is the right size
  339. Now take it out of the list */
  340. if (*head == node) {
  341. *head = node->next;
  342. } else {
  343. prevnode = *head;
  344. while (prevnode->next != node)
  345. prevnode = prevnode->next;
  346. prevnode->next = node->next;
  347. }
  348. node->next = NULL;
  349. /* Stop looping */
  350. break;
  351. }
  352. return node;
  353. }
  354. /**
  355. * get_resource_with_base - get resource with specific base address
  356. *
  357. * this function
  358. * returns the first node of "size" length located at specified base address.
  359. * If it finds a node larger than "size" it will split it up.
  360. *
  361. * size must be a power of two.
  362. *
  363. */
  364. struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
  365. {
  366. struct pci_resource *prevnode;
  367. struct pci_resource *node;
  368. struct pci_resource *split_node;
  369. u64 temp_qword;
  370. if (!(*head))
  371. return NULL;
  372. if (acpiphp_resource_sort_and_combine(head))
  373. return NULL;
  374. for (node = *head; node; node = node->next) {
  375. dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
  376. (u32)base, size, node, (u32)node->base, node->length);
  377. if (node->base > base)
  378. continue;
  379. if ((node->base + node->length) < (base + size))
  380. continue;
  381. if (node->base < base) {
  382. dbg(": split 1\n");
  383. /* this one isn't base aligned properly
  384. so we'll make a new entry and split it up */
  385. temp_qword = base;
  386. /* Short circuit if adjusted size is too small */
  387. if ((node->length - (temp_qword - node->base)) < size)
  388. continue;
  389. split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
  390. if (!split_node)
  391. return NULL;
  392. node->base = temp_qword;
  393. node->length -= split_node->length;
  394. /* Put it in the list */
  395. split_node->next = node->next;
  396. node->next = split_node;
  397. }
  398. dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
  399. (u32)base, size, node, (u32)node->base, node->length);
  400. /* Don't need to check if too small since we already did */
  401. if (node->length > size) {
  402. dbg(": split 2\n");
  403. /* this one is longer than we need
  404. so we'll make a new entry and split it up */
  405. split_node = acpiphp_make_resource(node->base + size, node->length - size);
  406. if (!split_node)
  407. return NULL;
  408. node->length = size;
  409. /* Put it in the list */
  410. split_node->next = node->next;
  411. node->next = split_node;
  412. } /* End of too big on top end */
  413. dbg(": got one!!!\n");
  414. /* If we got here, then it is the right size
  415. Now take it out of the list */
  416. if (*head == node) {
  417. *head = node->next;
  418. } else {
  419. prevnode = *head;
  420. while (prevnode->next != node)
  421. prevnode = prevnode->next;
  422. prevnode->next = node->next;
  423. }
  424. node->next = NULL;
  425. /* Stop looping */
  426. break;
  427. }
  428. return node;
  429. }
  430. /**
  431. * acpiphp_resource_sort_and_combine
  432. *
  433. * Sorts all of the nodes in the list in ascending order by
  434. * their base addresses. Also does garbage collection by
  435. * combining adjacent nodes.
  436. *
  437. * returns 0 if success
  438. */
  439. int acpiphp_resource_sort_and_combine (struct pci_resource **head)
  440. {
  441. struct pci_resource *node1;
  442. struct pci_resource *node2;
  443. int out_of_order = 1;
  444. if (!(*head))
  445. return 1;
  446. dbg("*head->next = %p\n",(*head)->next);
  447. if (!(*head)->next)
  448. return 0; /* only one item on the list, already sorted! */
  449. dbg("*head->base = 0x%x\n",(u32)(*head)->base);
  450. dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
  451. while (out_of_order) {
  452. out_of_order = 0;
  453. /* Special case for swapping list head */
  454. if (((*head)->next) &&
  455. ((*head)->base > (*head)->next->base)) {
  456. node1 = *head;
  457. (*head) = (*head)->next;
  458. node1->next = (*head)->next;
  459. (*head)->next = node1;
  460. out_of_order++;
  461. }
  462. node1 = (*head);
  463. while (node1->next && node1->next->next) {
  464. if (node1->next->base > node1->next->next->base) {
  465. out_of_order++;
  466. node2 = node1->next;
  467. node1->next = node1->next->next;
  468. node1 = node1->next;
  469. node2->next = node1->next;
  470. node1->next = node2;
  471. } else
  472. node1 = node1->next;
  473. }
  474. } /* End of out_of_order loop */
  475. node1 = *head;
  476. while (node1 && node1->next) {
  477. if ((node1->base + node1->length) == node1->next->base) {
  478. /* Combine */
  479. dbg("8..\n");
  480. node1->length += node1->next->length;
  481. node2 = node1->next;
  482. node1->next = node1->next->next;
  483. kfree(node2);
  484. } else
  485. node1 = node1->next;
  486. }
  487. return 0;
  488. }
  489. /**
  490. * acpiphp_make_resource - make resource structure
  491. * @base: base address of a resource
  492. * @length: length of a resource
  493. */
  494. struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
  495. {
  496. struct pci_resource *res;
  497. res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  498. if (res) {
  499. memset(res, 0, sizeof(struct pci_resource));
  500. res->base = base;
  501. res->length = length;
  502. }
  503. return res;
  504. }
  505. /**
  506. * acpiphp_move_resource - move linked resources from one to another
  507. * @from: head of linked resource list
  508. * @to: head of linked resource list
  509. */
  510. void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
  511. {
  512. struct pci_resource *tmp;
  513. while (*from) {
  514. tmp = (*from)->next;
  515. (*from)->next = *to;
  516. *to = *from;
  517. *from = tmp;
  518. }
  519. /* *from = NULL is guaranteed */
  520. }
  521. /**
  522. * acpiphp_free_resource - free all linked resources
  523. * @res: head of linked resource list
  524. */
  525. void acpiphp_free_resource (struct pci_resource **res)
  526. {
  527. struct pci_resource *tmp;
  528. while (*res) {
  529. tmp = (*res)->next;
  530. kfree(*res);
  531. *res = tmp;
  532. }
  533. /* *res = NULL is guaranteed */
  534. }
  535. /* debug support functions; will go away sometime :) */
  536. static void dump_resource(struct pci_resource *head)
  537. {
  538. struct pci_resource *p;
  539. int cnt;
  540. p = head;
  541. cnt = 0;
  542. while (p) {
  543. dbg("[%02d] %08x - %08x\n",
  544. cnt++, (u32)p->base, (u32)p->base + p->length - 1);
  545. p = p->next;
  546. }
  547. }
  548. void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
  549. {
  550. dbg("I/O resource:\n");
  551. dump_resource(bridge->io_head);
  552. dbg("MEM resource:\n");
  553. dump_resource(bridge->mem_head);
  554. dbg("PMEM resource:\n");
  555. dump_resource(bridge->p_mem_head);
  556. dbg("BUS resource:\n");
  557. dump_resource(bridge->bus_head);
  558. }
  559. void acpiphp_dump_func_resource(struct acpiphp_func *func)
  560. {
  561. dbg("I/O resource:\n");
  562. dump_resource(func->io_head);
  563. dbg("MEM resource:\n");
  564. dump_resource(func->mem_head);
  565. dbg("PMEM resource:\n");
  566. dump_resource(func->p_mem_head);
  567. dbg("BUS resource:\n");
  568. dump_resource(func->bus_head);
  569. }