aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/iseries/pci.c
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2007-12-07 00:10:22 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-10 21:46:11 -0500
commit1dee20262f4b16db73b2f24036bd423e8a7d693d (patch)
tree5556bf57ef7d71bf22343c48c3f20715df6cb56d /arch/powerpc/platforms/iseries/pci.c
parent1be9ad650986a87c25686abda97bdea330359708 (diff)
[POWERPC] iSeries: Merge vpdinfo.c into pci.c
There was only one global function in vpdinfo.c and it was only called from pci.c, so merge them and make the function static. Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/iseries/pci.c')
-rw-r--r--arch/powerpc/platforms/iseries/pci.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 5466975bc906..68f248b4c696 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) 2001 Allan Trautman, IBM Corporation 2 * Copyright (C) 2001 Allan Trautman, IBM Corporation
3 * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp
3 * 4 *
4 * iSeries specific routines for PCI. 5 * iSeries specific routines for PCI.
5 * 6 *
@@ -26,6 +27,7 @@
26#include <linux/module.h> 27#include <linux/module.h>
27#include <linux/pci.h> 28#include <linux/pci.h>
28 29
30#include <asm/types.h>
29#include <asm/io.h> 31#include <asm/io.h>
30#include <asm/irq.h> 32#include <asm/irq.h>
31#include <asm/prom.h> 33#include <asm/prom.h>
@@ -35,6 +37,7 @@
35#include <asm/abs_addr.h> 37#include <asm/abs_addr.h>
36#include <asm/firmware.h> 38#include <asm/firmware.h>
37 39
40#include <asm/iseries/hv_types.h>
38#include <asm/iseries/hv_call_xm.h> 41#include <asm/iseries/hv_call_xm.h>
39#include <asm/iseries/mf.h> 42#include <asm/iseries/mf.h>
40#include <asm/iseries/iommu.h> 43#include <asm/iseries/iommu.h>
@@ -80,6 +83,221 @@ static inline u64 iseries_ds_addr(struct device_node *node)
80} 83}
81 84
82/* 85/*
86 * Size of Bus VPD data
87 */
88#define BUS_VPDSIZE 1024
89
90/*
91 * Bus Vpd Tags
92 */
93#define VPD_END_OF_AREA 0x79
94#define VPD_ID_STRING 0x82
95#define VPD_VENDOR_AREA 0x84
96
97/*
98 * Mfg Area Tags
99 */
100#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */
101#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */
102#define VPD_SLOT_MAP 0x534D /* "SM" */
103
104/*
105 * Structures of the areas
106 */
107struct mfg_vpd_area {
108 u16 tag;
109 u8 length;
110 u8 data1;
111 u8 data2;
112};
113#define MFG_ENTRY_SIZE 3
114
115struct slot_map {
116 u8 agent;
117 u8 secondary_agent;
118 u8 phb;
119 char card_location[3];
120 char parms[8];
121 char reserved[2];
122};
123#define SLOT_ENTRY_SIZE 16
124
125/*
126 * Parse the Slot Area
127 */
128static void __init iseries_parse_slot_area(struct slot_map *map, int len,
129 HvAgentId agent, u8 *phb, char card[4])
130{
131 /*
132 * Parse Slot label until we find the one requested
133 */
134 while (len > 0) {
135 if (map->agent == agent) {
136 /*
137 * If Phb wasn't found, grab the entry first one found.
138 */
139 if (*phb == 0xff)
140 *phb = map->phb;
141 /* Found it, extract the data. */
142 if (map->phb == *phb) {
143 memcpy(card, &map->card_location, 3);
144 card[3] = 0;
145 break;
146 }
147 }
148 /* Point to the next Slot */
149 map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
150 len -= SLOT_ENTRY_SIZE;
151 }
152}
153
154/*
155 * Parse the Mfg Area
156 */
157static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
158 HvAgentId agent, u8 *phb, u8 *frame, char card[4])
159{
160 u16 slot_map_fmt = 0;
161
162 /* Parse Mfg Data */
163 while (len > 0) {
164 int mfg_tag_len = area->length;
165 /* Frame ID (FI 4649020310 ) */
166 if (area->tag == VPD_FRU_FRAME_ID)
167 *frame = area->data1;
168 /* Slot Map Format (MF 4D46020004 ) */
169 else if (area->tag == VPD_SLOT_MAP_FORMAT)
170 slot_map_fmt = (area->data1 * 256)
171 + area->data2;
172 /* Slot Map (SM 534D90 */
173 else if (area->tag == VPD_SLOT_MAP) {
174 struct slot_map *slot_map;
175
176 if (slot_map_fmt == 0x1004)
177 slot_map = (struct slot_map *)((char *)area
178 + MFG_ENTRY_SIZE + 1);
179 else
180 slot_map = (struct slot_map *)((char *)area
181 + MFG_ENTRY_SIZE);
182 iseries_parse_slot_area(slot_map, mfg_tag_len,
183 agent, phb, card);
184 }
185 /*
186 * Point to the next Mfg Area
187 * Use defined size, sizeof give wrong answer
188 */
189 area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
190 + MFG_ENTRY_SIZE);
191 len -= (mfg_tag_len + MFG_ENTRY_SIZE);
192 }
193}
194
195/*
196 * Look for "BUS".. Data is not Null terminated.
197 * PHBID of 0xFF indicates PHB was not found in VPD Data.
198 */
199static u8 __init iseries_parse_phbid(u8 *area, int len)
200{
201 while (len > 0) {
202 if ((*area == 'B') && (*(area + 1) == 'U')
203 && (*(area + 2) == 'S')) {
204 area += 3;
205 while (*area == ' ')
206 area++;
207 return *area & 0x0F;
208 }
209 area++;
210 len--;
211 }
212 return 0xff;
213}
214
215/*
216 * Parse out the VPD Areas
217 */
218static void __init iseries_parse_vpd(u8 *data, int data_len,
219 HvAgentId agent, u8 *frame, char card[4])
220{
221 u8 phb = 0xff;
222
223 while (data_len > 0) {
224 int len;
225 u8 tag = *data;
226
227 if (tag == VPD_END_OF_AREA)
228 break;
229 len = *(data + 1) + (*(data + 2) * 256);
230 data += 3;
231 data_len -= 3;
232 if (tag == VPD_ID_STRING)
233 phb = iseries_parse_phbid(data, len);
234 else if (tag == VPD_VENDOR_AREA)
235 iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
236 agent, &phb, frame, card);
237 /* Point to next Area. */
238 data += len;
239 data_len -= len;
240 }
241}
242
243static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
244 u8 *frame, char card[4])
245{
246 int status = 0;
247 int bus_vpd_len = 0;
248 u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
249
250 if (bus_vpd == NULL) {
251 printk("PCI: Bus VPD Buffer allocation failure.\n");
252 return 0;
253 }
254 bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
255 BUS_VPDSIZE);
256 if (bus_vpd_len == 0) {
257 printk("PCI: Bus VPD Buffer zero length.\n");
258 goto out_free;
259 }
260 /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
261 /* Make sure this is what I think it is */
262 if (*bus_vpd != VPD_ID_STRING) {
263 printk("PCI: Bus VPD Buffer missing starting tag.\n");
264 goto out_free;
265 }
266 iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
267 status = 1;
268out_free:
269 kfree(bus_vpd);
270 return status;
271}
272
273/*
274 * Prints the device information.
275 * - Pass in pci_dev* pointer to the device.
276 * - Pass in the device count
277 *
278 * Format:
279 * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
280 * controller
281 */
282static void __init iseries_device_information(struct pci_dev *pdev, int count,
283 u16 bus, HvSubBusNumber subbus)
284{
285 u8 frame = 0;
286 char card[4];
287 HvAgentId agent;
288
289 agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
290 ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
291
292 if (iseries_get_location_code(bus, agent, &frame, card)) {
293 printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
294 "Card %4s 0x%04X\n", count, bus,
295 PCI_SLOT(pdev->devfn), pdev->vendor, frame,
296 card, (int)(pdev->class >> 8));
297 }
298}
299
300/*
83 * iomm_table_allocate_entry 301 * iomm_table_allocate_entry
84 * 302 *
85 * Adds pci_dev entry in address translation table 303 * Adds pci_dev entry in address translation table