1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 2006 Silicon Graphics, Inc. All rights reserved.
7 */
8
9#include <asm/sn/types.h>
10#include <asm/sn/addrs.h>
11#include <asm/sn/pcidev.h>
12#include <asm/sn/pcibus_provider_defs.h>
13#include <asm/sn/sn_sal.h>
14#include "xtalk/hubdev.h"
15#include <linux/acpi.h>
16#include <linux/slab.h>
17#include <linux/export.h>
18
19
20/*
21 * The code in this file will only be executed when running with
22 * a PROM that has ACPI IO support. (i.e., SN_ACPI_BASE_SUPPORT() == 1)
23 */
24
25
26/*
27 * This value must match the UUID the PROM uses
28 * (io/acpi/defblk.c) when building a vendor descriptor.
29 */
30struct acpi_vendor_uuid sn_uuid = {
31	.subtype = 0,
32	.data	= { 0x2c, 0xc6, 0xa6, 0xfe, 0x9c, 0x44, 0xda, 0x11,
33		    0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
34};
35
36struct sn_pcidev_match {
37	u8 bus;
38	unsigned int devfn;
39	acpi_handle handle;
40};
41
42/*
43 * Perform the early IO init in PROM.
44 */
45static long
46sal_ioif_init(u64 *result)
47{
48	struct ia64_sal_retval isrv = {0,0,0,0};
49
50	SAL_CALL_NOLOCK(isrv,
51			SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0);
52	*result = isrv.v0;
53	return isrv.status;
54}
55
56/*
57 * sn_acpi_hubdev_init() - This function is called by acpi_ns_get_device_callback()
58 *			   for all SGIHUB and SGITIO acpi devices defined in the
59 *			   DSDT. It obtains the hubdev_info pointer from the
60 *			   ACPI vendor resource, which the PROM setup, and sets up the
61 *			   hubdev_info in the pda.
62 */
63
64static acpi_status __init
65sn_acpi_hubdev_init(acpi_handle handle, u32 depth, void *context, void **ret)
66{
67	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
68	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
69	u64 addr;
70	struct hubdev_info *hubdev;
71	struct hubdev_info *hubdev_ptr;
72	int i;
73	u64 nasid;
74	struct acpi_resource *resource;
75	acpi_status status;
76	struct acpi_resource_vendor_typed *vendor;
77	extern void sn_common_hubdev_init(struct hubdev_info *);
78
79	status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
80					  &sn_uuid, &buffer);
81	if (ACPI_FAILURE(status)) {
82		acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
83		printk(KERN_ERR
84		       "sn_acpi_hubdev_init: acpi_get_vendor_resource() "
85		       "(0x%x) failed for: %s\n", status,
86			(char *)name_buffer.pointer);
87		kfree(name_buffer.pointer);
88		return AE_OK;		/* Continue walking namespace */
89	}
90
91	resource = buffer.pointer;
92	vendor = &resource->data.vendor_typed;
93	if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
94	    sizeof(struct hubdev_info *)) {
95		acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
96		printk(KERN_ERR
97		       "sn_acpi_hubdev_init: Invalid vendor data length: "
98		       "%d for: %s\n",
99			vendor->byte_length, (char *)name_buffer.pointer);
100		kfree(name_buffer.pointer);
101		goto exit;
102	}
103
104	memcpy(&addr, vendor->byte_data, sizeof(struct hubdev_info *));
105	hubdev_ptr = __va((struct hubdev_info *) addr);
106
107	nasid = hubdev_ptr->hdi_nasid;
108	i = nasid_to_cnodeid(nasid);
109	hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
110	*hubdev = *hubdev_ptr;
111	sn_common_hubdev_init(hubdev);
112
113exit:
114	kfree(buffer.pointer);
115	return AE_OK;		/* Continue walking namespace */
116}
117
118/*
119 * sn_get_bussoft_ptr() - The pcibus_bussoft pointer is found in
120 *			  the ACPI Vendor resource for this bus.
121 */
122static struct pcibus_bussoft *
123sn_get_bussoft_ptr(struct pci_bus *bus)
124{
125	u64 addr;
126	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
127	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
128	acpi_handle handle;
129	struct pcibus_bussoft *prom_bussoft_ptr;
130	struct acpi_resource *resource;
131	acpi_status status;
132	struct acpi_resource_vendor_typed *vendor;
133
134
135	handle = acpi_device_handle(PCI_CONTROLLER(bus)->companion);
136	status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
137					  &sn_uuid, &buffer);
138	if (ACPI_FAILURE(status)) {
139		acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
140		printk(KERN_ERR "%s: "
141		       "acpi_get_vendor_resource() failed (0x%x) for: %s\n",
142		       __func__, status, (char *)name_buffer.pointer);
143		kfree(name_buffer.pointer);
144		return NULL;
145	}
146	resource = buffer.pointer;
147	vendor = &resource->data.vendor_typed;
148
149	if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
150	     sizeof(struct pcibus_bussoft *)) {
151		printk(KERN_ERR
152		       "%s: Invalid vendor data length %d\n",
153			__func__, vendor->byte_length);
154		kfree(buffer.pointer);
155		return NULL;
156	}
157	memcpy(&addr, vendor->byte_data, sizeof(struct pcibus_bussoft *));
158	prom_bussoft_ptr = __va((struct pcibus_bussoft *) addr);
159	kfree(buffer.pointer);
160
161	return prom_bussoft_ptr;
162}
163
164/*
165 * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info
166 *			    pointers from the vendor resource using the
167 *			    provided acpi handle, and copy the structures
168 *			    into the argument buffers.
169 */
170static int
171sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info,
172		    struct sn_irq_info **sn_irq_info)
173{
174	u64 addr;
175	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
176	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
177	struct sn_irq_info *irq_info, *irq_info_prom;
178	struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr;
179	struct acpi_resource *resource;
180	int ret = 0;
181	acpi_status status;
182	struct acpi_resource_vendor_typed *vendor;
183
184	/*
185	 * The pointer to this device's pcidev_info structure in
186	 * the PROM, is in the vendor resource.
187	 */
188	status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
189					  &sn_uuid, &buffer);
190	if (ACPI_FAILURE(status)) {
191		acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
192		printk(KERN_ERR
193		       "%s: acpi_get_vendor_resource() failed (0x%x) for: %s\n",
194			__func__, status, (char *)name_buffer.pointer);
195		kfree(name_buffer.pointer);
196		return 1;
197	}
198
199	resource = buffer.pointer;
200	vendor = &resource->data.vendor_typed;
201	if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
202	    sizeof(struct pci_devdev_info *)) {
203		acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
204		printk(KERN_ERR
205		       "%s: Invalid vendor data length: %d for: %s\n",
206			 __func__, vendor->byte_length,
207			(char *)name_buffer.pointer);
208		kfree(name_buffer.pointer);
209		ret = 1;
210		goto exit;
211	}
212
213	pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
214	if (!pcidev_ptr)
215		panic("%s: Unable to alloc memory for pcidev_info", __func__);
216
217	memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *));
218	pcidev_prom_ptr = __va(addr);
219	memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info));
220
221	/* Get the IRQ info */
222	irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
223	if (!irq_info)
224		 panic("%s: Unable to alloc memory for sn_irq_info", __func__);
225
226	if (pcidev_ptr->pdi_sn_irq_info) {
227		irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info);
228		memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info));
229	}
230
231	*pcidev_info = pcidev_ptr;
232	*sn_irq_info = irq_info;
233
234exit:
235	kfree(buffer.pointer);
236	return ret;
237}
238
239static unsigned int
240get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
241{
242	unsigned long long adr;
243	acpi_handle child;
244	unsigned int devfn;
245	int function;
246	acpi_handle parent;
247	int slot;
248	acpi_status status;
249	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
250
251	acpi_get_name(device_handle, ACPI_FULL_PATHNAME, &name_buffer);
252
253	/*
254	 * Do an upward search to find the root bus device, and
255	 * obtain the host devfn from the previous child device.
256	 */
257	child = device_handle;
258	while (child) {
259		status = acpi_get_parent(child, &parent);
260		if (ACPI_FAILURE(status)) {
261			printk(KERN_ERR "%s: acpi_get_parent() failed "
262			       "(0x%x) for: %s\n", __func__, status,
263				(char *)name_buffer.pointer);
264			panic("%s: Unable to find host devfn\n", __func__);
265		}
266		if (parent == rootbus_handle)
267			break;
268		child = parent;
269	}
270	if (!child) {
271		printk(KERN_ERR "%s: Unable to find root bus for: %s\n",
272		       __func__, (char *)name_buffer.pointer);
273		BUG();
274	}
275
276	status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr);
277	if (ACPI_FAILURE(status)) {
278		printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: %s\n",
279		       __func__, status, (char *)name_buffer.pointer);
280		panic("%s: Unable to find host devfn\n", __func__);
281	}
282
283	kfree(name_buffer.pointer);
284
285	slot = (adr >> 16) & 0xffff;
286	function = adr & 0xffff;
287	devfn = PCI_DEVFN(slot, function);
288	return devfn;
289}
290
291/*
292 * find_matching_device - Callback routine to find the ACPI device
293 *			  that matches up with our pci_dev device.
294 *			  Matching is done on bus number and devfn.
295 *			  To find the bus number for a particular
296 *			  ACPI device, we must look at the _BBN method
297 *			  of its parent.
298 */
299static acpi_status
300find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
301{
302	unsigned long long bbn = -1;
303	unsigned long long adr;
304	acpi_handle parent = NULL;
305	acpi_status status;
306	unsigned int devfn;
307	int function;
308	int slot;
309	struct sn_pcidev_match *info = context;
310	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
311
312        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
313                                       &adr);
314        if (ACPI_SUCCESS(status)) {
315		status = acpi_get_parent(handle, &parent);
316		if (ACPI_FAILURE(status)) {
317			acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
318			printk(KERN_ERR
319			       "%s: acpi_get_parent() failed (0x%x) for: %s\n",
320				__func__, status, (char *)name_buffer.pointer);
321			kfree(name_buffer.pointer);
322			return AE_OK;
323		}
324		status = acpi_evaluate_integer(parent, METHOD_NAME__BBN,
325					       NULL, &bbn);
326		if (ACPI_FAILURE(status)) {
327			acpi_get_name(handle, ACPI_FULL_PATHNAME, &name_buffer);
328			printk(KERN_ERR
329			  "%s: Failed to find _BBN in parent of: %s\n",
330					__func__, (char *)name_buffer.pointer);
331			kfree(name_buffer.pointer);
332			return AE_OK;
333		}
334
335                slot = (adr >> 16) & 0xffff;
336                function = adr & 0xffff;
337                devfn = PCI_DEVFN(slot, function);
338                if ((info->devfn == devfn) && (info->bus == bbn)) {
339			/* We have a match! */
340			info->handle = handle;
341			return 1;
342		}
343	}
344	return AE_OK;
345}
346
347/*
348 * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi
349 *			     device matching the specified pci_dev,
350 *			     and return the pcidev info and irq info.
351 */
352int
353sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
354			struct sn_irq_info **sn_irq_info)
355{
356	unsigned int host_devfn;
357	struct sn_pcidev_match pcidev_match;
358	acpi_handle rootbus_handle;
359	unsigned long long segment;
360	acpi_status status;
361	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
362
363	rootbus_handle = acpi_device_handle(PCI_CONTROLLER(dev)->companion);
364        status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
365                                       &segment);
366        if (ACPI_SUCCESS(status)) {
367		if (segment != pci_domain_nr(dev)) {
368			acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME,
369				&name_buffer);
370			printk(KERN_ERR
371			       "%s: Segment number mismatch, 0x%llx vs 0x%x for: %s\n",
372			       __func__, segment, pci_domain_nr(dev),
373			       (char *)name_buffer.pointer);
374			kfree(name_buffer.pointer);
375			return 1;
376		}
377	} else {
378		acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME, &name_buffer);
379		printk(KERN_ERR "%s: Unable to get __SEG from: %s\n",
380		       __func__, (char *)name_buffer.pointer);
381		kfree(name_buffer.pointer);
382		return 1;
383	}
384
385	/*
386	 * We want to search all devices in this segment/domain
387	 * of the ACPI namespace for the matching ACPI device,
388	 * which holds the pcidev_info pointer in its vendor resource.
389	 */
390	pcidev_match.bus = dev->bus->number;
391	pcidev_match.devfn = dev->devfn;
392	pcidev_match.handle = NULL;
393
394	acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
395			    find_matching_device, NULL, &pcidev_match, NULL);
396
397	if (!pcidev_match.handle) {
398		printk(KERN_ERR
399		       "%s: Could not find matching ACPI device for %s.\n",
400		       __func__, pci_name(dev));
401		return 1;
402	}
403
404	if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info))
405		return 1;
406
407	/* Build up the pcidev_info.pdi_slot_host_handle */
408	host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
409	(*pcidev_info)->pdi_slot_host_handle =
410			((unsigned long) pci_domain_nr(dev) << 40) |
411					/* bus == 0 */
412					host_devfn;
413	return 0;
414}
415
416/*
417 * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info.
418 *			Perform any SN specific slot fixup.
419 *			At present there does not appear to be
420 *			any generic way to handle a ROM image
421 *			that has been shadowed by the PROM, so
422 *			we pass a pointer to it	within the
423 *			pcidev_info structure.
424 */
425
426void
427sn_acpi_slot_fixup(struct pci_dev *dev)
428{
429	void __iomem *addr;
430	struct pcidev_info *pcidev_info = NULL;
431	struct sn_irq_info *sn_irq_info = NULL;
432	size_t image_size, size;
433
434	if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
435		panic("%s:  Failure obtaining pcidev_info for %s\n",
436		      __func__, pci_name(dev));
437	}
438
439	if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
440		/*
441		 * A valid ROM image exists and has been shadowed by the
442		 * PROM. Setup the pci_dev ROM resource with the address
443		 * of the shadowed copy, and the actual length of the ROM image.
444		 */
445		size = pci_resource_len(dev, PCI_ROM_RESOURCE);
446		addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE],
447			       size);
448		image_size = pci_get_rom_size(dev, addr, size);
449		dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr;
450		dev->resource[PCI_ROM_RESOURCE].end =
451					(unsigned long) addr + image_size - 1;
452		dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
453	}
454	sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
455}
456
457EXPORT_SYMBOL(sn_acpi_slot_fixup);
458
459
460/*
461 * sn_acpi_bus_fixup -  Perform SN specific setup of software structs
462 *			(pcibus_bussoft, pcidev_info) and hardware
463 *			registers, for the specified bus and devices under it.
464 */
465void
466sn_acpi_bus_fixup(struct pci_bus *bus)
467{
468	struct pci_dev *pci_dev = NULL;
469	struct pcibus_bussoft *prom_bussoft_ptr;
470
471	if (!bus->parent) {	/* If root bus */
472		prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
473		if (prom_bussoft_ptr == NULL) {
474			printk(KERN_ERR
475			       "%s: 0x%04x:0x%02x Unable to "
476			       "obtain prom_bussoft_ptr\n",
477			       __func__, pci_domain_nr(bus), bus->number);
478			return;
479		}
480		sn_common_bus_fixup(bus, prom_bussoft_ptr);
481	}
482	list_for_each_entry(pci_dev, &bus->devices, bus_list) {
483		sn_acpi_slot_fixup(pci_dev);
484	}
485}
486
487/*
488 * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
489 *		     nodes and root buses in the DSDT. As a result, bus scanning
490 *		     will be initiated by the Linux ACPI code.
491 */
492
493void __init
494sn_io_acpi_init(void)
495{
496	u64 result;
497	long status;
498
499	/* SN Altix does not follow the IOSAPIC IRQ routing model */
500	acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
501
502	/* Setup hubdev_info for all SGIHUB/SGITIO devices */
503	acpi_get_devices("SGIHUB", sn_acpi_hubdev_init, NULL, NULL);
504	acpi_get_devices("SGITIO", sn_acpi_hubdev_init, NULL, NULL);
505
506	status = sal_ioif_init(&result);
507	if (status || result)
508		panic("sal_ioif_init failed: [%lx] %s\n",
509		      status, ia64_sal_strerror(status));
510}
511