vpdinfo.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * This code gets the card location of the hardware
  3. * Copyright (C) 2001 <Allan H Trautman> <IBM Corp>
  4. * Copyright (C) 2005 Stephen Rothwel, IBM Corp
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the:
  18. * Free Software Foundation, Inc.,
  19. * 59 Temple Place, Suite 330,
  20. * Boston, MA 02111-1307 USA
  21. *
  22. * Change Activity:
  23. * Created, Feb 2, 2001
  24. * Ported to ppc64, August 20, 2001
  25. * End Change Activity
  26. */
  27. #include <linux/init.h>
  28. #include <linux/module.h>
  29. #include <linux/pci.h>
  30. #include <asm/types.h>
  31. #include <asm/resource.h>
  32. #include <asm/abs_addr.h>
  33. #include <asm/pci-bridge.h>
  34. #include <asm/iseries/hv_types.h>
  35. #include "pci.h"
  36. #include "call_pci.h"
  37. /*
  38. * Size of Bus VPD data
  39. */
  40. #define BUS_VPDSIZE 1024
  41. /*
  42. * Bus Vpd Tags
  43. */
  44. #define VpdEndOfAreaTag 0x79
  45. #define VpdIdStringTag 0x82
  46. #define VpdVendorAreaTag 0x84
  47. /*
  48. * Mfg Area Tags
  49. */
  50. #define VpdFruFrameId 0x4649 // "FI"
  51. #define VpdSlotMapFormat 0x4D46 // "MF"
  52. #define VpdSlotMap 0x534D // "SM"
  53. /*
  54. * Structures of the areas
  55. */
  56. struct MfgVpdAreaStruct {
  57. u16 Tag;
  58. u8 TagLength;
  59. u8 AreaData1;
  60. u8 AreaData2;
  61. };
  62. typedef struct MfgVpdAreaStruct MfgArea;
  63. #define MFG_ENTRY_SIZE 3
  64. struct SlotMapStruct {
  65. u8 AgentId;
  66. u8 SecondaryAgentId;
  67. u8 PhbId;
  68. char CardLocation[3];
  69. char Parms[8];
  70. char Reserved[2];
  71. };
  72. typedef struct SlotMapStruct SlotMap;
  73. #define SLOT_ENTRY_SIZE 16
  74. /*
  75. * Parse the Slot Area
  76. */
  77. static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
  78. HvAgentId agent, u8 *PhbId, char card[4])
  79. {
  80. int SlotMapLen = MapLen;
  81. SlotMap *SlotMapPtr = MapPtr;
  82. /*
  83. * Parse Slot label until we find the one requested
  84. */
  85. while (SlotMapLen > 0) {
  86. if (SlotMapPtr->AgentId == agent) {
  87. /*
  88. * If Phb wasn't found, grab the entry first one found.
  89. */
  90. if (*PhbId == 0xff)
  91. *PhbId = SlotMapPtr->PhbId;
  92. /* Found it, extract the data. */
  93. if (SlotMapPtr->PhbId == *PhbId) {
  94. memcpy(card, &SlotMapPtr->CardLocation, 3);
  95. card[3] = 0;
  96. break;
  97. }
  98. }
  99. /* Point to the next Slot */
  100. SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE);
  101. SlotMapLen -= SLOT_ENTRY_SIZE;
  102. }
  103. }
  104. /*
  105. * Parse the Mfg Area
  106. */
  107. static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
  108. HvAgentId agent, u8 *PhbId,
  109. u8 *frame, char card[4])
  110. {
  111. MfgArea *MfgAreaPtr = (MfgArea *)AreaData;
  112. int MfgAreaLen = AreaLen;
  113. u16 SlotMapFmt = 0;
  114. /* Parse Mfg Data */
  115. while (MfgAreaLen > 0) {
  116. int MfgTagLen = MfgAreaPtr->TagLength;
  117. /* Frame ID (FI 4649020310 ) */
  118. if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */
  119. *frame = MfgAreaPtr->AreaData1;
  120. /* Slot Map Format (MF 4D46020004 ) */
  121. else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */
  122. SlotMapFmt = (MfgAreaPtr->AreaData1 * 256)
  123. + MfgAreaPtr->AreaData2;
  124. /* Slot Map (SM 534D90 */
  125. else if (MfgAreaPtr->Tag == VpdSlotMap) { /* SM */
  126. SlotMap *SlotMapPtr;
  127. if (SlotMapFmt == 0x1004)
  128. SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
  129. + MFG_ENTRY_SIZE + 1);
  130. else
  131. SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
  132. + MFG_ENTRY_SIZE);
  133. iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen,
  134. agent, PhbId, card);
  135. }
  136. /*
  137. * Point to the next Mfg Area
  138. * Use defined size, sizeof give wrong answer
  139. */
  140. MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen
  141. + MFG_ENTRY_SIZE);
  142. MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
  143. }
  144. }
  145. /*
  146. * Look for "BUS".. Data is not Null terminated.
  147. * PHBID of 0xFF indicates PHB was not found in VPD Data.
  148. */
  149. static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
  150. {
  151. u8 *PhbPtr = AreaPtr;
  152. int DataLen = AreaLength;
  153. char PhbId = 0xFF;
  154. while (DataLen > 0) {
  155. if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U')
  156. && (*(PhbPtr + 2) == 'S')) {
  157. PhbPtr += 3;
  158. while (*PhbPtr == ' ')
  159. ++PhbPtr;
  160. PhbId = (*PhbPtr & 0x0F);
  161. break;
  162. }
  163. ++PhbPtr;
  164. --DataLen;
  165. }
  166. return PhbId;
  167. }
  168. /*
  169. * Parse out the VPD Areas
  170. */
  171. static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
  172. HvAgentId agent, u8 *frame, char card[4])
  173. {
  174. u8 *TagPtr = VpdData;
  175. int DataLen = VpdDataLen - 3;
  176. u8 PhbId = 0xff;
  177. while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
  178. int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
  179. u8 *AreaData = TagPtr + 3;
  180. if (*TagPtr == VpdIdStringTag)
  181. PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
  182. else if (*TagPtr == VpdVendorAreaTag)
  183. iSeries_Parse_MfgArea(AreaData, AreaLen,
  184. agent, &PhbId, frame, card);
  185. /* Point to next Area. */
  186. TagPtr = AreaData + AreaLen;
  187. DataLen -= AreaLen;
  188. }
  189. }
  190. static int __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
  191. u8 *frame, char card[4])
  192. {
  193. int status = 0;
  194. int BusVpdLen = 0;
  195. u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
  196. if (BusVpdPtr == NULL) {
  197. printk("PCI: Bus VPD Buffer allocation failure.\n");
  198. return 0;
  199. }
  200. BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr),
  201. BUS_VPDSIZE);
  202. if (BusVpdLen == 0) {
  203. printk("PCI: Bus VPD Buffer zero length.\n");
  204. goto out_free;
  205. }
  206. /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */
  207. /* Make sure this is what I think it is */
  208. if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */
  209. printk("PCI: Bus VPD Buffer missing starting tag.\n");
  210. goto out_free;
  211. }
  212. iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
  213. status = 1;
  214. out_free:
  215. kfree(BusVpdPtr);
  216. return status;
  217. }
  218. /*
  219. * Prints the device information.
  220. * - Pass in pci_dev* pointer to the device.
  221. * - Pass in the device count
  222. *
  223. * Format:
  224. * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
  225. * controller
  226. */
  227. void __init iSeries_Device_Information(struct pci_dev *PciDev, int count)
  228. {
  229. struct device_node *DevNode = PciDev->sysdata;
  230. struct pci_dn *pdn;
  231. u16 bus;
  232. u8 frame = 0;
  233. char card[4];
  234. HvSubBusNumber subbus;
  235. HvAgentId agent;
  236. if (DevNode == NULL) {
  237. printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n",
  238. count);
  239. return;
  240. }
  241. pdn = PCI_DN(DevNode);
  242. bus = pdn->busno;
  243. subbus = pdn->bussubno;
  244. agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
  245. ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
  246. if (iSeries_Get_Location_Code(bus, agent, &frame, card)) {
  247. printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
  248. "Card %4s 0x%04X\n", count, bus,
  249. PCI_SLOT(PciDev->devfn), PciDev->vendor, frame,
  250. card, (int)(PciDev->class >> 8));
  251. }
  252. }