vpdinfo.c 6.7 KB

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