shpchprm_legacy.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform
  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) 2003-2004 Intel Corporation
  8. *
  9. * All rights reserved.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or (at
  14. * your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  19. * NON INFRINGEMENT. See the GNU General Public License for more
  20. * details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25. *
  26. * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
  27. *
  28. */
  29. #include <linux/config.h>
  30. #include <linux/module.h>
  31. #include <linux/kernel.h>
  32. #include <linux/types.h>
  33. #include <linux/pci.h>
  34. #include <linux/init.h>
  35. #include <asm/uaccess.h>
  36. #ifdef CONFIG_IA64
  37. #include <asm/iosapic.h>
  38. #endif
  39. #include "shpchp.h"
  40. #include "shpchprm.h"
  41. #include "shpchprm_legacy.h"
  42. static void __iomem *shpchp_rom_start;
  43. static u16 unused_IRQ;
  44. void shpchprm_cleanup(void)
  45. {
  46. if (shpchp_rom_start)
  47. iounmap(shpchp_rom_start);
  48. }
  49. int shpchprm_print_pirt(void)
  50. {
  51. return 0;
  52. }
  53. int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
  54. {
  55. int offset = devnum - ctrl->slot_device_offset;
  56. *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset);
  57. return 0;
  58. }
  59. /* Find the Hot Plug Resource Table in the specified region of memory */
  60. static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
  61. {
  62. void __iomem *fp;
  63. void __iomem *endp;
  64. u8 temp1, temp2, temp3, temp4;
  65. int status = 0;
  66. endp = (end - sizeof(struct hrt) + 1);
  67. for (fp = begin; fp <= endp; fp += 16) {
  68. temp1 = readb(fp + SIG0);
  69. temp2 = readb(fp + SIG1);
  70. temp3 = readb(fp + SIG2);
  71. temp4 = readb(fp + SIG3);
  72. if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') {
  73. status = 1;
  74. break;
  75. }
  76. }
  77. if (!status)
  78. fp = NULL;
  79. dbg("Discovered Hotplug Resource Table at %p\n", fp);
  80. return fp;
  81. }
  82. /*
  83. * shpchprm_find_available_resources
  84. *
  85. * Finds available memory, IO, and IRQ resources for programming
  86. * devices which may be added to the system
  87. * this function is for hot plug ADD!
  88. *
  89. * returns 0 if success
  90. */
  91. int shpchprm_find_available_resources(struct controller *ctrl)
  92. {
  93. u8 populated_slot;
  94. u8 bridged_slot;
  95. void __iomem *one_slot;
  96. struct pci_func *func = NULL;
  97. int i = 10, index = 0;
  98. u32 temp_dword, rc;
  99. ulong temp_ulong;
  100. struct pci_resource *mem_node;
  101. struct pci_resource *p_mem_node;
  102. struct pci_resource *io_node;
  103. struct pci_resource *bus_node;
  104. void __iomem *rom_resource_table;
  105. struct pci_bus lpci_bus, *pci_bus;
  106. u8 cfgspc_irq, temp;
  107. memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
  108. pci_bus = &lpci_bus;
  109. rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff);
  110. dbg("rom_resource_table = %p\n", rom_resource_table);
  111. if (rom_resource_table == NULL)
  112. return -ENODEV;
  113. /* Sum all resources and setup resource maps */
  114. unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
  115. dbg("unused_IRQ = %x\n", unused_IRQ);
  116. temp = 0;
  117. while (unused_IRQ) {
  118. if (unused_IRQ & 1) {
  119. shpchp_disk_irq = temp;
  120. break;
  121. }
  122. unused_IRQ = unused_IRQ >> 1;
  123. temp++;
  124. }
  125. dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq);
  126. unused_IRQ = unused_IRQ >> 1;
  127. temp++;
  128. while (unused_IRQ) {
  129. if (unused_IRQ & 1) {
  130. shpchp_nic_irq = temp;
  131. break;
  132. }
  133. unused_IRQ = unused_IRQ >> 1;
  134. temp++;
  135. }
  136. dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq);
  137. unused_IRQ = readl(rom_resource_table + PCIIRQ);
  138. temp = 0;
  139. pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq);
  140. if (!shpchp_nic_irq) {
  141. shpchp_nic_irq = cfgspc_irq;
  142. }
  143. if (!shpchp_disk_irq) {
  144. shpchp_disk_irq = cfgspc_irq;
  145. }
  146. dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq);
  147. one_slot = rom_resource_table + sizeof(struct hrt);
  148. i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
  149. dbg("number_of_entries = %d\n", i);
  150. if (!readb(one_slot + SECONDARY_BUS))
  151. return (1);
  152. dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n");
  153. while (i && readb(one_slot + SECONDARY_BUS)) {
  154. u8 dev_func = readb(one_slot + DEV_FUNC);
  155. u8 primary_bus = readb(one_slot + PRIMARY_BUS);
  156. u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
  157. u8 max_bus = readb(one_slot + MAX_BUS);
  158. u16 io_base = readw(one_slot + IO_BASE);
  159. u16 io_length = readw(one_slot + IO_LENGTH);
  160. u16 mem_base = readw(one_slot + MEM_BASE);
  161. u16 mem_length = readw(one_slot + MEM_LENGTH);
  162. u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
  163. u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
  164. dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
  165. dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
  166. primary_bus, secondary_bus, max_bus);
  167. /* If this entry isn't for our controller's bus, ignore it */
  168. if (primary_bus != ctrl->slot_bus) {
  169. i--;
  170. one_slot += sizeof(struct slot_rt);
  171. continue;
  172. }
  173. /* find out if this entry is for an occupied slot */
  174. temp_dword = 0xFFFFFFFF;
  175. pci_bus->number = primary_bus;
  176. pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
  177. dbg("temp_D_word = %x\n", temp_dword);
  178. if (temp_dword != 0xFFFFFFFF) {
  179. index = 0;
  180. func = shpchp_slot_find(primary_bus, dev_func >> 3, 0);
  181. while (func && (func->function != (dev_func & 0x07))) {
  182. dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index);
  183. func = shpchp_slot_find(primary_bus, dev_func >> 3, index++);
  184. }
  185. /* If we can't find a match, skip this table entry */
  186. if (!func) {
  187. i--;
  188. one_slot += sizeof(struct slot_rt);
  189. continue;
  190. }
  191. /* this may not work and shouldn't be used */
  192. if (secondary_bus != primary_bus)
  193. bridged_slot = 1;
  194. else
  195. bridged_slot = 0;
  196. populated_slot = 1;
  197. } else {
  198. populated_slot = 0;
  199. bridged_slot = 0;
  200. }
  201. dbg("slot populated =%s \n", populated_slot?"yes":"no");
  202. /* If we've got a valid IO base, use it */
  203. temp_ulong = io_base + io_length;
  204. if ((io_base) && (temp_ulong <= 0x10000)) {
  205. io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  206. if (!io_node)
  207. return -ENOMEM;
  208. io_node->base = (ulong)io_base;
  209. io_node->length = (ulong)io_length;
  210. dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length);
  211. if (!populated_slot) {
  212. io_node->next = ctrl->io_head;
  213. ctrl->io_head = io_node;
  214. } else {
  215. io_node->next = func->io_head;
  216. func->io_head = io_node;
  217. }
  218. }
  219. /* If we've got a valid memory base, use it */
  220. temp_ulong = mem_base + mem_length;
  221. if ((mem_base) && (temp_ulong <= 0x10000)) {
  222. mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  223. if (!mem_node)
  224. return -ENOMEM;
  225. mem_node->base = (ulong)mem_base << 16;
  226. mem_node->length = (ulong)(mem_length << 16);
  227. dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length);
  228. if (!populated_slot) {
  229. mem_node->next = ctrl->mem_head;
  230. ctrl->mem_head = mem_node;
  231. } else {
  232. mem_node->next = func->mem_head;
  233. func->mem_head = mem_node;
  234. }
  235. }
  236. /*
  237. * If we've got a valid prefetchable memory base, and
  238. * the base + length isn't greater than 0xFFFF
  239. */
  240. temp_ulong = pre_mem_base + pre_mem_length;
  241. if ((pre_mem_base) && (temp_ulong <= 0x10000)) {
  242. p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  243. if (!p_mem_node)
  244. return -ENOMEM;
  245. p_mem_node->base = (ulong)pre_mem_base << 16;
  246. p_mem_node->length = (ulong)pre_mem_length << 16;
  247. dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length);
  248. if (!populated_slot) {
  249. p_mem_node->next = ctrl->p_mem_head;
  250. ctrl->p_mem_head = p_mem_node;
  251. } else {
  252. p_mem_node->next = func->p_mem_head;
  253. func->p_mem_head = p_mem_node;
  254. }
  255. }
  256. /*
  257. * If we've got a valid bus number, use it
  258. * The second condition is to ignore bus numbers on
  259. * populated slots that don't have PCI-PCI bridges
  260. */
  261. if (secondary_bus && (secondary_bus != primary_bus)) {
  262. bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
  263. if (!bus_node)
  264. return -ENOMEM;
  265. bus_node->base = (ulong)secondary_bus;
  266. bus_node->length = (ulong)(max_bus - secondary_bus + 1);
  267. dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length);
  268. if (!populated_slot) {
  269. bus_node->next = ctrl->bus_head;
  270. ctrl->bus_head = bus_node;
  271. } else {
  272. bus_node->next = func->bus_head;
  273. func->bus_head = bus_node;
  274. }
  275. }
  276. i--;
  277. one_slot += sizeof(struct slot_rt);
  278. }
  279. /* If all of the following fail, we don't have any resources for hot plug add */
  280. rc = 1;
  281. rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head));
  282. rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
  283. rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head));
  284. rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head));
  285. return (rc);
  286. }
  287. int shpchprm_set_hpp(
  288. struct controller *ctrl,
  289. struct pci_func *func,
  290. u8 card_type)
  291. {
  292. u32 rc;
  293. u8 temp_byte;
  294. struct pci_bus lpci_bus, *pci_bus;
  295. unsigned int devfn;
  296. memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
  297. pci_bus = &lpci_bus;
  298. pci_bus->number = func->bus;
  299. devfn = PCI_DEVFN(func->device, func->function);
  300. temp_byte = 0x40; /* hard coded value for LT */
  301. if (card_type == PCI_HEADER_TYPE_BRIDGE) {
  302. /* set subordinate Latency Timer */
  303. rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
  304. if (rc) {
  305. dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus,
  306. func->device, func->function);
  307. return rc;
  308. }
  309. }
  310. /* set base Latency Timer */
  311. rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
  312. if (rc) {
  313. dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
  314. return rc;
  315. }
  316. /* set Cache Line size */
  317. temp_byte = 0x08; /* hard coded value for CLS */
  318. rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
  319. if (rc) {
  320. dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
  321. }
  322. /* set enable_perr */
  323. /* set enable_serr */
  324. return rc;
  325. }
  326. void shpchprm_enable_card(
  327. struct controller *ctrl,
  328. struct pci_func *func,
  329. u8 card_type)
  330. {
  331. u16 command, bcommand;
  332. struct pci_bus lpci_bus, *pci_bus;
  333. unsigned int devfn;
  334. int rc;
  335. memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
  336. pci_bus = &lpci_bus;
  337. pci_bus->number = func->bus;
  338. devfn = PCI_DEVFN(func->device, func->function);
  339. rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
  340. command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
  341. | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
  342. | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
  343. rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
  344. if (card_type == PCI_HEADER_TYPE_BRIDGE) {
  345. rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
  346. bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
  347. | PCI_BRIDGE_CTL_NO_ISA;
  348. rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
  349. }
  350. }
  351. static int legacy_shpchprm_init_pci(void)
  352. {
  353. shpchp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
  354. if (!shpchp_rom_start) {
  355. err("Could not ioremap memory region for ROM\n");
  356. return -EIO;
  357. }
  358. return 0;
  359. }
  360. int shpchprm_init(enum php_ctlr_type ctrl_type)
  361. {
  362. int retval;
  363. switch (ctrl_type) {
  364. case PCI:
  365. retval = legacy_shpchprm_init_pci();
  366. break;
  367. default:
  368. retval = -ENODEV;
  369. break;
  370. }
  371. return retval;
  372. }