PageRenderTime 44ms CodeModel.GetById 18ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/ia64/sn/kernel/io_init.c

https://bitbucket.org/evzijst/gittest
C | 411 lines | 269 code | 72 blank | 70 comment | 30 complexity | 17d0f44111abce2c281899922dc0ac28 MD5 | raw file
  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) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
  7 */
  8
  9#include <linux/bootmem.h>
 10#include <linux/nodemask.h>
 11#include <asm/sn/types.h>
 12#include <asm/sn/sn_sal.h>
 13#include <asm/sn/addrs.h>
 14#include "pci/pcibus_provider_defs.h"
 15#include "pci/pcidev.h"
 16#include "pci/pcibr_provider.h"
 17#include "xtalk/xwidgetdev.h"
 18#include <asm/sn/geo.h>
 19#include "xtalk/hubdev.h"
 20#include <asm/sn/io.h>
 21#include <asm/sn/simulator.h>
 22
 23char master_baseio_wid;
 24nasid_t master_nasid = INVALID_NASID;	/* Partition Master */
 25
 26struct slab_info {
 27	struct hubdev_info hubdev;
 28};
 29
 30struct brick {
 31	moduleid_t id;		/* Module ID of this module        */
 32	struct slab_info slab_info[MAX_SLABS + 1];
 33};
 34
 35int sn_ioif_inited = 0;		/* SN I/O infrastructure initialized? */
 36
 37/*
 38 * Retrieve the DMA Flush List given nasid.  This list is needed 
 39 * to implement the WAR - Flush DMA data on PIO Reads.
 40 */
 41static inline uint64_t
 42sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
 43{
 44
 45	struct ia64_sal_retval ret_stuff;
 46	ret_stuff.status = 0;
 47	ret_stuff.v0 = 0;
 48
 49	SAL_CALL_NOLOCK(ret_stuff,
 50			(u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
 51			(u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0,
 52			0);
 53	return ret_stuff.v0;
 54
 55}
 56
 57/*
 58 * Retrieve the hub device info structure for the given nasid.
 59 */
 60static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
 61{
 62
 63	struct ia64_sal_retval ret_stuff;
 64	ret_stuff.status = 0;
 65	ret_stuff.v0 = 0;
 66
 67	SAL_CALL_NOLOCK(ret_stuff,
 68			(u64) SN_SAL_IOIF_GET_HUBDEV_INFO,
 69			(u64) handle, (u64) address, 0, 0, 0, 0, 0);
 70	return ret_stuff.v0;
 71}
 72
 73/*
 74 * Retrieve the pci bus information given the bus number.
 75 */
 76static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 77{
 78
 79	struct ia64_sal_retval ret_stuff;
 80	ret_stuff.status = 0;
 81	ret_stuff.v0 = 0;
 82
 83	SAL_CALL_NOLOCK(ret_stuff,
 84			(u64) SN_SAL_IOIF_GET_PCIBUS_INFO,
 85			(u64) segment, (u64) busnum, (u64) address, 0, 0, 0, 0);
 86	return ret_stuff.v0;
 87}
 88
 89/*
 90 * Retrieve the pci device information given the bus and device|function number.
 91 */
 92static inline uint64_t
 93sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 
 94			u64 sn_irq_info)
 95{
 96	struct ia64_sal_retval ret_stuff;
 97	ret_stuff.status = 0;
 98	ret_stuff.v0 = 0;
 99
100	SAL_CALL_NOLOCK(ret_stuff,
101			(u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
102			(u64) segment, (u64) bus_number, (u64) devfn, 
103			(u64) pci_dev,
104			sn_irq_info, 0, 0);
105	return ret_stuff.v0;
106}
107
108/*
109 * sn_alloc_pci_sysdata() - This routine allocates a pci controller
110 *	which is expected as the pci_dev and pci_bus sysdata by the Linux
111 *	PCI infrastructure.
112 */
113static inline struct pci_controller *sn_alloc_pci_sysdata(void)
114{
115	struct pci_controller *pci_sysdata;
116
117	pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
118	if (!pci_sysdata)
119		BUG();
120
121	memset(pci_sysdata, 0, sizeof(*pci_sysdata));
122	return pci_sysdata;
123}
124
125/*
126 * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
127 *	each node in the system.
128 */
129static void sn_fixup_ionodes(void)
130{
131
132	struct sn_flush_device_list *sn_flush_device_list;
133	struct hubdev_info *hubdev;
134	uint64_t status;
135	uint64_t nasid;
136	int i, widget;
137
138	for (i = 0; i < numionodes; i++) {
139		hubdev = (struct hubdev_info *)(NODEPDA(i)->pdinfo);
140		nasid = cnodeid_to_nasid(i);
141		status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
142		if (status)
143			continue;
144
145		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++)
146			hubdev->hdi_xwidget_info[widget].xwi_hubinfo = hubdev;
147
148		if (!hubdev->hdi_flush_nasid_list.widget_p)
149			continue;
150
151		hubdev->hdi_flush_nasid_list.widget_p =
152		    kmalloc((HUB_WIDGET_ID_MAX + 1) *
153			    sizeof(struct sn_flush_device_list *), GFP_KERNEL);
154
155		memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
156		       (HUB_WIDGET_ID_MAX + 1) *
157		       sizeof(struct sn_flush_device_list *));
158
159		for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
160			sn_flush_device_list = kmalloc(DEV_PER_WIDGET *
161						       sizeof(struct
162							      sn_flush_device_list),
163						       GFP_KERNEL);
164			memset(sn_flush_device_list, 0x0,
165			       DEV_PER_WIDGET *
166			       sizeof(struct sn_flush_device_list));
167
168			status =
169			    sal_get_widget_dmaflush_list(nasid, widget,
170							 (uint64_t)
171							 __pa
172							 (sn_flush_device_list));
173			if (status) {
174				kfree(sn_flush_device_list);
175				continue;
176			}
177
178			hubdev->hdi_flush_nasid_list.widget_p[widget] =
179			    sn_flush_device_list;
180		}
181
182		if (!(i & 1))
183			hub_error_init(hubdev);
184		else
185			ice_error_init(hubdev);
186	}
187
188}
189
190/*
191 * sn_pci_fixup_slot() - This routine sets up a slot's resources
192 * consistent with the Linux PCI abstraction layer.  Resources acquired
193 * from our PCI provider include PIO maps to BAR space and interrupt
194 * objects.
195 */
196static void sn_pci_fixup_slot(struct pci_dev *dev)
197{
198	int idx;
199	int segment = 0;
200	uint64_t size;
201	struct sn_irq_info *sn_irq_info;
202	struct pci_dev *host_pci_dev;
203	int status = 0;
204
205	dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
206	if (SN_PCIDEV_INFO(dev) <= 0)
207		BUG();		/* Cannot afford to run out of memory */
208	memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));
209
210	sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
211	if (sn_irq_info <= 0)
212		BUG();		/* Cannot afford to run out of memory */
213	memset(sn_irq_info, 0, sizeof(struct sn_irq_info));
214
215	/* Call to retrieve pci device information needed by kernel. */
216	status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
217				     dev->devfn,
218				     (u64) __pa(SN_PCIDEV_INFO(dev)),
219				     (u64) __pa(sn_irq_info));
220	if (status)
221		BUG();		/* Cannot get platform pci device information information */
222
223	/* Copy over PIO Mapped Addresses */
224	for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
225		unsigned long start, end, addr;
226
227		if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx])
228			continue;
229
230		start = dev->resource[idx].start;
231		end = dev->resource[idx].end;
232		size = end - start;
233		addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx];
234		addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
235		dev->resource[idx].start = addr;
236		dev->resource[idx].end = addr + size;
237		if (dev->resource[idx].flags & IORESOURCE_IO)
238			dev->resource[idx].parent = &ioport_resource;
239		else
240			dev->resource[idx].parent = &iomem_resource;
241	}
242
243	/* set up host bus linkages */
244	host_pci_dev =
245	    pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
246			  SN_PCIDEV_INFO(dev)->
247			  pdi_slot_host_handle & 0xffffffff);
248	SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
249	    SN_PCIDEV_INFO(host_pci_dev);
250	SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
251	SN_PCIDEV_INFO(dev)->pdi_pcibus_info = SN_PCIBUS_BUSSOFT(dev->bus);
252
253	/* Only set up IRQ stuff if this device has a host bus context */
254	if (SN_PCIDEV_BUSSOFT(dev) && sn_irq_info->irq_irq) {
255		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
256		dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
257		sn_irq_fixup(dev, sn_irq_info);
258	}
259}
260
261/*
262 * sn_pci_controller_fixup() - This routine sets up a bus's resources
263 * consistent with the Linux PCI abstraction layer.
264 */
265static void sn_pci_controller_fixup(int segment, int busnum)
266{
267	int status = 0;
268	int nasid, cnode;
269	struct pci_bus *bus;
270	struct pci_controller *controller;
271	struct pcibus_bussoft *prom_bussoft_ptr;
272	struct hubdev_info *hubdev_info;
273	void *provider_soft;
274
275	status =
276	    sal_get_pcibus_info((u64) segment, (u64) busnum,
277				(u64) ia64_tpa(&prom_bussoft_ptr));
278	if (status > 0) {
279		return;		/* bus # does not exist */
280	}
281
282	prom_bussoft_ptr = __va(prom_bussoft_ptr);
283	controller = sn_alloc_pci_sysdata();
284	/* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
285
286	bus = pci_scan_bus(busnum, &pci_root_ops, controller);
287	if (bus == NULL) {
288		return;		/* error, or bus already scanned */
289	}
290
291	/*
292	 * Per-provider fixup.  Copies the contents from prom to local
293	 * area and links SN_PCIBUS_BUSSOFT().
294	 *
295	 * Note:  Provider is responsible for ensuring that prom_bussoft_ptr
296	 * represents an asic-type that it can handle.
297	 */
298
299	if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) {
300		return;		/* no further fixup necessary */
301	}
302
303	provider_soft = pcibr_bus_fixup(prom_bussoft_ptr);
304	if (provider_soft == NULL) {
305		return;		/* fixup failed or not applicable */
306	}
307
308	/*
309	 * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
310	 * after this point.
311	 */
312
313	bus->sysdata = controller;
314	PCI_CONTROLLER(bus)->platform_data = provider_soft;
315
316	nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
317	cnode = nasid_to_cnodeid(nasid);
318	hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
319	SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
320	    &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
321}
322
323/*
324 * Ugly hack to get PCI setup until we have a proper ACPI namespace.
325 */
326
327#define PCI_BUSES_TO_SCAN 256
328
329static int __init sn_pci_init(void)
330{
331	int i = 0;
332	struct pci_dev *pci_dev = NULL;
333	extern void sn_init_cpei_timer(void);
334#ifdef CONFIG_PROC_FS
335	extern void register_sn_procfs(void);
336#endif
337
338	if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR())
339		return 0;
340
341	/*
342	 * This is needed to avoid bounce limit checks in the blk layer
343	 */
344	ia64_max_iommu_merge_mask = ~PAGE_MASK;
345	sn_fixup_ionodes();
346	sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL);
347	if (sn_irq <= 0)
348		BUG();		/* Canno afford to run out of memory. */
349	memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS);
350
351	sn_init_cpei_timer();
352
353#ifdef CONFIG_PROC_FS
354	register_sn_procfs();
355#endif
356
357	for (i = 0; i < PCI_BUSES_TO_SCAN; i++) {
358		sn_pci_controller_fixup(0, i);
359	}
360
361	/*
362	 * Generic Linux PCI Layer has created the pci_bus and pci_dev 
363	 * structures - time for us to add our SN PLatform specific 
364	 * information.
365	 */
366
367	while ((pci_dev =
368		pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
369		sn_pci_fixup_slot(pci_dev);
370	}
371
372	sn_ioif_inited = 1;	/* sn I/O infrastructure now initialized */
373
374	return 0;
375}
376
377/*
378 * hubdev_init_node() - Creates the HUB data structure and link them to it's 
379 *	own NODE specific data area.
380 */
381void hubdev_init_node(nodepda_t * npda, cnodeid_t node)
382{
383
384	struct hubdev_info *hubdev_info;
385
386	if (node >= num_online_nodes())	/* Headless/memless IO nodes */
387		hubdev_info =
388		    (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(0),
389							     sizeof(struct
390								    hubdev_info));
391	else
392		hubdev_info =
393		    (struct hubdev_info *)alloc_bootmem_node(NODE_DATA(node),
394							     sizeof(struct
395								    hubdev_info));
396	npda->pdinfo = (void *)hubdev_info;
397
398}
399
400geoid_t
401cnodeid_get_geoid(cnodeid_t cnode)
402{
403
404	struct hubdev_info *hubdev;
405
406	hubdev = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
407	return hubdev->hdi_geoid;
408
409}
410
411subsys_initcall(sn_pci_init);