vpdinfo.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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/iSeries/HvCallPci.h>
  33. #include <asm/iSeries/HvTypes.h>
  34. #include <asm/iSeries/iSeries_pci.h>
  35. /*
  36. * Size of Bus VPD data
  37. */
  38. #define BUS_VPDSIZE 1024
  39. /*
  40. * Bus Vpd Tags
  41. */
  42. #define VpdEndOfAreaTag 0x79
  43. #define VpdIdStringTag 0x82
  44. #define VpdVendorAreaTag 0x84
  45. /*
  46. * Mfg Area Tags
  47. */
  48. #define VpdFruFrameId 0x4649 // "FI"
  49. #define VpdSlotMapFormat 0x4D46 // "MF"
  50. #define VpdSlotMap 0x534D // "SM"
  51. /*
  52. * Structures of the areas
  53. */
  54. struct MfgVpdAreaStruct {
  55. u16 Tag;
  56. u8 TagLength;
  57. u8 AreaData1;
  58. u8 AreaData2;
  59. };
  60. typedef struct MfgVpdAreaStruct MfgArea;
  61. #define MFG_ENTRY_SIZE 3
  62. struct SlotMapStruct {
  63. u8 AgentId;
  64. u8 SecondaryAgentId;
  65. u8 PhbId;
  66. char CardLocation[3];
  67. char Parms[8];
  68. char Reserved[2];
  69. };
  70. typedef struct SlotMapStruct SlotMap;
  71. #define SLOT_ENTRY_SIZE 16
  72. /*
  73. * Parse the Slot Area
  74. */
  75. static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
  76. HvAgentId agent, u8 *PhbId, char card[4])
  77. {
  78. int SlotMapLen = MapLen;
  79. SlotMap *SlotMapPtr = MapPtr;
  80. /*
  81. * Parse Slot label until we find the one requested
  82. */
  83. while (SlotMapLen > 0) {
  84. if (SlotMapPtr->AgentId == agent) {
  85. /*
  86. * If Phb wasn't found, grab the entry first one found.
  87. */
  88. if (*PhbId == 0xff)
  89. *PhbId = SlotMapPtr->PhbId;
  90. /* Found it, extract the data. */
  91. if (SlotMapPtr->PhbId == *PhbId) {
  92. memcpy(card, &SlotMapPtr->CardLocation, 3);
  93. card[3] = 0;
  94. break;
  95. }
  96. }
  97. /* Point to the next Slot */
  98. SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE);
  99. SlotMapLen -= SLOT_ENTRY_SIZE;
  100. }
  101. }
  102. /*
  103. * Parse the Mfg Area
  104. */
  105. static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
  106. HvAgentId agent, u8 *PhbId,
  107. u8 *frame, char card[4])
  108. {
  109. MfgArea *MfgAreaPtr = (MfgArea *)AreaData;
  110. int MfgAreaLen = AreaLen;
  111. u16 SlotMapFmt = 0;
  112. /* Parse Mfg Data */
  113. while (MfgAreaLen > 0) {
  114. int MfgTagLen = MfgAreaPtr->TagLength;
  115. /* Frame ID (FI 4649020310 ) */
  116. if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */
  117. *frame = MfgAreaPtr->AreaData1;
  118. /* Slot Map Format (MF 4D46020004 ) */
  119. else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */
  120. SlotMapFmt = (MfgAreaPtr->AreaData1 * 256)
  121. + MfgAreaPtr->AreaData2;
  122. /* Slot Map (SM 534D90 */
  123. else if (MfgAreaPtr->Tag == VpdSlotMap) { /* SM */
  124. SlotMap *SlotMapPtr;
  125. if (SlotMapFmt == 0x1004)
  126. SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
  127. + MFG_ENTRY_SIZE + 1);
  128. else
  129. SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
  130. + MFG_ENTRY_SIZE);
  131. iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen,
  132. agent, PhbId, card);
  133. }
  134. /*
  135. * Point to the next Mfg Area
  136. * Use defined size, sizeof give wrong answer
  137. */
  138. MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen
  139. + MFG_ENTRY_SIZE);
  140. MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
  141. }
  142. }
  143. /*
  144. * Look for "BUS".. Data is not Null terminated.
  145. * PHBID of 0xFF indicates PHB was not found in VPD Data.
  146. */
  147. static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
  148. {
  149. u8 *PhbPtr = AreaPtr;
  150. int DataLen = AreaLength;
  151. char PhbId = 0xFF;
  152. while (DataLen > 0) {
  153. if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U')
  154. && (*(PhbPtr + 2) == 'S')) {
  155. PhbPtr += 3;
  156. while (*PhbPtr == ' ')
  157. ++PhbPtr;
  158. PhbId = (*PhbPtr & 0x0F);
  159. break;
  160. }
  161. ++PhbPtr;
  162. --DataLen;
  163. }
  164. return PhbId;
  165. }
  166. /*
  167. * Parse out the VPD Areas
  168. */
  169. static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
  170. HvAgentId agent, u8 *frame, char card[4])
  171. {
  172. u8 *TagPtr = VpdData;
  173. int DataLen = VpdDataLen - 3;
  174. u8 PhbId;
  175. while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
  176. int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
  177. u8 *AreaData = TagPtr + 3;
  178. if (*TagPtr == VpdIdStringTag)
  179. PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
  180. else if (*TagPtr == VpdVendorAreaTag)
  181. iSeries_Parse_MfgArea(AreaData, AreaLen,
  182. agent, &PhbId, frame, card);
  183. /* Point to next Area. */
  184. TagPtr = AreaData + AreaLen;
  185. DataLen -= AreaLen;
  186. }
  187. }
  188. static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
  189. u8 *frame, char card[4])
  190. {
  191. int BusVpdLen = 0;
  192. u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
  193. if (BusVpdPtr == NULL) {
  194. printk("PCI: Bus VPD Buffer allocation failure.\n");
  195. return;
  196. }
  197. BusVpdLen = HvCallPci_getBusVpd(bus, ISERIES_HV_ADDR(BusVpdPtr),
  198. BUS_VPDSIZE);
  199. if (BusVpdLen == 0) {
  200. printk("PCI: Bus VPD Buffer zero length.\n");
  201. goto out_free;
  202. }
  203. /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */
  204. /* Make sure this is what I think it is */
  205. if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */
  206. printk("PCI: Bus VPD Buffer missing starting tag.\n");
  207. goto out_free;
  208. }
  209. iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
  210. out_free:
  211. kfree(BusVpdPtr);
  212. }
  213. /*
  214. * Prints the device information.
  215. * - Pass in pci_dev* pointer to the device.
  216. * - Pass in the device count
  217. *
  218. * Format:
  219. * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
  220. * controller
  221. */
  222. void __init iSeries_Device_Information(struct pci_dev *PciDev, int count)
  223. {
  224. struct device_node *DevNode = PciDev->sysdata;
  225. u16 bus;
  226. u8 frame;
  227. char card[4];
  228. HvSubBusNumber subbus;
  229. HvAgentId agent;
  230. if (DevNode == NULL) {
  231. printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n",
  232. count);
  233. return;
  234. }
  235. bus = ISERIES_BUS(DevNode);
  236. subbus = ISERIES_SUBBUS(DevNode);
  237. agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
  238. ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
  239. iSeries_Get_Location_Code(bus, agent, &frame, card);
  240. printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ",
  241. count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor,
  242. frame, card);
  243. printk("0x%04X\n", (int)(PciDev->class >> 8));
  244. }