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