Commit | Line | Data |
---|---|---|
9c90bdde MM |
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) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. | |
7 | */ | |
8 | ||
9 | #include <linux/types.h> | |
10 | #include <linux/interrupt.h> | |
11 | #include <linux/pci.h> | |
81f6527b | 12 | #include <linux/bitmap.h> |
5a0e3ad6 | 13 | #include <linux/slab.h> |
9c90bdde MM |
14 | #include <asm/sn/sn_sal.h> |
15 | #include <asm/sn/addrs.h> | |
1fa92957 | 16 | #include <asm/sn/io.h> |
9c90bdde MM |
17 | #include <asm/sn/pcidev.h> |
18 | #include <asm/sn/pcibus_provider_defs.h> | |
19 | #include <asm/sn/tioca_provider.h> | |
20 | ||
53493dcf | 21 | u32 tioca_gart_found; |
9c90bdde MM |
22 | EXPORT_SYMBOL(tioca_gart_found); /* used by agp-sgi */ |
23 | ||
24 | LIST_HEAD(tioca_list); | |
25 | EXPORT_SYMBOL(tioca_list); /* used by agp-sgi */ | |
26 | ||
27 | static int tioca_gart_init(struct tioca_kernel *); | |
28 | ||
29 | /** | |
30 | * tioca_gart_init - Initialize SGI TIOCA GART | |
31 | * @tioca_common: ptr to common prom/kernel struct identifying the | |
32 | * | |
33 | * If the indicated tioca has devices present, initialize its associated | |
34 | * GART MMR's and kernel memory. | |
35 | */ | |
36 | static int | |
37 | tioca_gart_init(struct tioca_kernel *tioca_kern) | |
38 | { | |
53493dcf PB |
39 | u64 ap_reg; |
40 | u64 offset; | |
9c90bdde MM |
41 | struct page *tmp; |
42 | struct tioca_common *tioca_common; | |
b3e5b5b2 | 43 | struct tioca __iomem *ca_base; |
9c90bdde MM |
44 | |
45 | tioca_common = tioca_kern->ca_common; | |
b3e5b5b2 | 46 | ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; |
9c90bdde MM |
47 | |
48 | if (list_empty(tioca_kern->ca_devices)) | |
49 | return 0; | |
50 | ||
51 | ap_reg = 0; | |
52 | ||
53 | /* | |
54 | * Validate aperature size | |
55 | */ | |
56 | ||
57 | switch (CA_APERATURE_SIZE >> 20) { | |
58 | case 4: | |
59 | ap_reg |= (0x3ff << CA_GART_AP_SIZE_SHFT); /* 4MB */ | |
60 | break; | |
61 | case 8: | |
62 | ap_reg |= (0x3fe << CA_GART_AP_SIZE_SHFT); /* 8MB */ | |
63 | break; | |
64 | case 16: | |
65 | ap_reg |= (0x3fc << CA_GART_AP_SIZE_SHFT); /* 16MB */ | |
66 | break; | |
67 | case 32: | |
68 | ap_reg |= (0x3f8 << CA_GART_AP_SIZE_SHFT); /* 32 MB */ | |
69 | break; | |
70 | case 64: | |
71 | ap_reg |= (0x3f0 << CA_GART_AP_SIZE_SHFT); /* 64 MB */ | |
72 | break; | |
73 | case 128: | |
74 | ap_reg |= (0x3e0 << CA_GART_AP_SIZE_SHFT); /* 128 MB */ | |
75 | break; | |
76 | case 256: | |
77 | ap_reg |= (0x3c0 << CA_GART_AP_SIZE_SHFT); /* 256 MB */ | |
78 | break; | |
79 | case 512: | |
80 | ap_reg |= (0x380 << CA_GART_AP_SIZE_SHFT); /* 512 MB */ | |
81 | break; | |
82 | case 1024: | |
83 | ap_reg |= (0x300 << CA_GART_AP_SIZE_SHFT); /* 1GB */ | |
84 | break; | |
85 | case 2048: | |
86 | ap_reg |= (0x200 << CA_GART_AP_SIZE_SHFT); /* 2GB */ | |
87 | break; | |
88 | case 4096: | |
89 | ap_reg |= (0x000 << CA_GART_AP_SIZE_SHFT); /* 4 GB */ | |
90 | break; | |
91 | default: | |
92 | printk(KERN_ERR "%s: Invalid CA_APERATURE_SIZE " | |
d4ed8084 | 93 | "0x%lx\n", __func__, (ulong) CA_APERATURE_SIZE); |
9c90bdde MM |
94 | return -1; |
95 | } | |
96 | ||
97 | /* | |
98 | * Set up other aperature parameters | |
99 | */ | |
100 | ||
101 | if (PAGE_SIZE >= 16384) { | |
102 | tioca_kern->ca_ap_pagesize = 16384; | |
103 | ap_reg |= CA_GART_PAGE_SIZE; | |
104 | } else { | |
105 | tioca_kern->ca_ap_pagesize = 4096; | |
106 | } | |
107 | ||
108 | tioca_kern->ca_ap_size = CA_APERATURE_SIZE; | |
109 | tioca_kern->ca_ap_bus_base = CA_APERATURE_BASE; | |
110 | tioca_kern->ca_gart_entries = | |
111 | tioca_kern->ca_ap_size / tioca_kern->ca_ap_pagesize; | |
112 | ||
113 | ap_reg |= (CA_GART_AP_ENB_AGP | CA_GART_AP_ENB_PCI); | |
114 | ap_reg |= tioca_kern->ca_ap_bus_base; | |
115 | ||
116 | /* | |
117 | * Allocate and set up the GART | |
118 | */ | |
119 | ||
120 | tioca_kern->ca_gart_size = tioca_kern->ca_gart_entries * sizeof(u64); | |
121 | tmp = | |
122 | alloc_pages_node(tioca_kern->ca_closest_node, | |
123 | GFP_KERNEL | __GFP_ZERO, | |
124 | get_order(tioca_kern->ca_gart_size)); | |
125 | ||
126 | if (!tmp) { | |
127 | printk(KERN_ERR "%s: Could not allocate " | |
e088a4ad | 128 | "%llu bytes (order %d) for GART\n", |
d4ed8084 | 129 | __func__, |
9c90bdde MM |
130 | tioca_kern->ca_gart_size, |
131 | get_order(tioca_kern->ca_gart_size)); | |
132 | return -ENOMEM; | |
133 | } | |
134 | ||
135 | tioca_kern->ca_gart = page_address(tmp); | |
136 | tioca_kern->ca_gart_coretalk_addr = | |
137 | PHYS_TO_TIODMA(virt_to_phys(tioca_kern->ca_gart)); | |
138 | ||
139 | /* | |
140 | * Compute PCI/AGP convenience fields | |
141 | */ | |
142 | ||
143 | offset = CA_PCI32_MAPPED_BASE - CA_APERATURE_BASE; | |
144 | tioca_kern->ca_pciap_base = CA_PCI32_MAPPED_BASE; | |
145 | tioca_kern->ca_pciap_size = CA_PCI32_MAPPED_SIZE; | |
146 | tioca_kern->ca_pcigart_start = offset / tioca_kern->ca_ap_pagesize; | |
147 | tioca_kern->ca_pcigart_base = | |
148 | tioca_kern->ca_gart_coretalk_addr + offset; | |
149 | tioca_kern->ca_pcigart = | |
150 | &tioca_kern->ca_gart[tioca_kern->ca_pcigart_start]; | |
151 | tioca_kern->ca_pcigart_entries = | |
152 | tioca_kern->ca_pciap_size / tioca_kern->ca_ap_pagesize; | |
153 | tioca_kern->ca_pcigart_pagemap = | |
f96cb1f0 | 154 | kzalloc(tioca_kern->ca_pcigart_entries / 8, GFP_KERNEL); |
9c90bdde MM |
155 | if (!tioca_kern->ca_pcigart_pagemap) { |
156 | free_pages((unsigned long)tioca_kern->ca_gart, | |
157 | get_order(tioca_kern->ca_gart_size)); | |
158 | return -1; | |
159 | } | |
160 | ||
161 | offset = CA_AGP_MAPPED_BASE - CA_APERATURE_BASE; | |
162 | tioca_kern->ca_gfxap_base = CA_AGP_MAPPED_BASE; | |
163 | tioca_kern->ca_gfxap_size = CA_AGP_MAPPED_SIZE; | |
164 | tioca_kern->ca_gfxgart_start = offset / tioca_kern->ca_ap_pagesize; | |
165 | tioca_kern->ca_gfxgart_base = | |
166 | tioca_kern->ca_gart_coretalk_addr + offset; | |
167 | tioca_kern->ca_gfxgart = | |
168 | &tioca_kern->ca_gart[tioca_kern->ca_gfxgart_start]; | |
169 | tioca_kern->ca_gfxgart_entries = | |
170 | tioca_kern->ca_gfxap_size / tioca_kern->ca_ap_pagesize; | |
171 | ||
172 | /* | |
173 | * various control settings: | |
174 | * use agp op-combining | |
175 | * use GET semantics to fetch memory | |
176 | * participate in coherency domain | |
4628d7ca | 177 | * DISABLE GART PREFETCHING due to hw bug tracked in SGI PV930029 |
9c90bdde MM |
178 | */ |
179 | ||
5fbcf9a5 MM |
180 | __sn_setq_relaxed(&ca_base->ca_control1, |
181 | CA_AGPDMA_OP_ENB_COMBDELAY); /* PV895469 ? */ | |
182 | __sn_clrq_relaxed(&ca_base->ca_control2, CA_GART_MEM_PARAM); | |
183 | __sn_setq_relaxed(&ca_base->ca_control2, | |
184 | (0x2ull << CA_GART_MEM_PARAM_SHFT)); | |
9c90bdde | 185 | tioca_kern->ca_gart_iscoherent = 1; |
5fbcf9a5 MM |
186 | __sn_clrq_relaxed(&ca_base->ca_control2, |
187 | (CA_GART_WR_PREFETCH_ENB | CA_GART_RD_PREFETCH_ENB)); | |
9c90bdde MM |
188 | |
189 | /* | |
190 | * Unmask GART fetch error interrupts. Clear residual errors first. | |
191 | */ | |
192 | ||
5fbcf9a5 MM |
193 | writeq(CA_GART_FETCH_ERR, &ca_base->ca_int_status_alias); |
194 | writeq(CA_GART_FETCH_ERR, &ca_base->ca_mult_error_alias); | |
195 | __sn_clrq_relaxed(&ca_base->ca_int_mask, CA_GART_FETCH_ERR); | |
9c90bdde MM |
196 | |
197 | /* | |
198 | * Program the aperature and gart registers in TIOCA | |
199 | */ | |
200 | ||
5fbcf9a5 MM |
201 | writeq(ap_reg, &ca_base->ca_gart_aperature); |
202 | writeq(tioca_kern->ca_gart_coretalk_addr|1, &ca_base->ca_gart_ptr_table); | |
9c90bdde MM |
203 | |
204 | return 0; | |
205 | } | |
206 | ||
207 | /** | |
208 | * tioca_fastwrite_enable - enable AGP FW for a tioca and its functions | |
209 | * @tioca_kernel: structure representing the CA | |
210 | * | |
211 | * Given a CA, scan all attached functions making sure they all support | |
212 | * FastWrite. If so, enable FastWrite for all functions and the CA itself. | |
213 | */ | |
214 | ||
215 | void | |
216 | tioca_fastwrite_enable(struct tioca_kernel *tioca_kern) | |
217 | { | |
218 | int cap_ptr; | |
53493dcf | 219 | u32 reg; |
b3e5b5b2 | 220 | struct tioca __iomem *tioca_base; |
9c90bdde MM |
221 | struct pci_dev *pdev; |
222 | struct tioca_common *common; | |
223 | ||
224 | common = tioca_kern->ca_common; | |
225 | ||
226 | /* | |
227 | * Scan all vga controllers on this bus making sure they all | |
72fdbdce | 228 | * support FW. If not, return. |
9c90bdde MM |
229 | */ |
230 | ||
231 | list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { | |
232 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) | |
233 | continue; | |
234 | ||
235 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | |
236 | if (!cap_ptr) | |
237 | return; /* no AGP CAP means no FW */ | |
238 | ||
239 | pci_read_config_dword(pdev, cap_ptr + PCI_AGP_STATUS, ®); | |
240 | if (!(reg & PCI_AGP_STATUS_FW)) | |
241 | return; /* function doesn't support FW */ | |
242 | } | |
243 | ||
244 | /* | |
245 | * Set fw for all vga fn's | |
246 | */ | |
247 | ||
248 | list_for_each_entry(pdev, tioca_kern->ca_devices, bus_list) { | |
249 | if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8)) | |
250 | continue; | |
251 | ||
252 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | |
253 | pci_read_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, ®); | |
254 | reg |= PCI_AGP_COMMAND_FW; | |
255 | pci_write_config_dword(pdev, cap_ptr + PCI_AGP_COMMAND, reg); | |
256 | } | |
257 | ||
258 | /* | |
259 | * Set ca's fw to match | |
260 | */ | |
261 | ||
b3e5b5b2 | 262 | tioca_base = (struct tioca __iomem*)common->ca_common.bs_base; |
5fbcf9a5 | 263 | __sn_setq_relaxed(&tioca_base->ca_control1, CA_AGP_FW_ENABLE); |
9c90bdde MM |
264 | } |
265 | ||
266 | EXPORT_SYMBOL(tioca_fastwrite_enable); /* used by agp-sgi */ | |
267 | ||
268 | /** | |
269 | * tioca_dma_d64 - create a DMA mapping using 64-bit direct mode | |
270 | * @paddr: system physical address | |
271 | * | |
272 | * Map @paddr into 64-bit CA bus space. No device context is necessary. | |
273 | * Bits 53:0 come from the coretalk address. We just need to mask in the | |
274 | * following optional bits of the 64-bit pci address: | |
275 | * | |
276 | * 63:60 - Coretalk Packet Type - 0x1 for Mem Get/Put (coherent) | |
277 | * 0x2 for PIO (non-coherent) | |
278 | * We will always use 0x1 | |
279 | * 55:55 - Swap bytes Currently unused | |
280 | */ | |
53493dcf | 281 | static u64 |
9c90bdde MM |
282 | tioca_dma_d64(unsigned long paddr) |
283 | { | |
284 | dma_addr_t bus_addr; | |
285 | ||
286 | bus_addr = PHYS_TO_TIODMA(paddr); | |
287 | ||
288 | BUG_ON(!bus_addr); | |
289 | BUG_ON(bus_addr >> 54); | |
290 | ||
291 | /* Set upper nibble to Cache Coherent Memory op */ | |
292 | bus_addr |= (1UL << 60); | |
293 | ||
294 | return bus_addr; | |
295 | } | |
296 | ||
297 | /** | |
298 | * tioca_dma_d48 - create a DMA mapping using 48-bit direct mode | |
299 | * @pdev: linux pci_dev representing the function | |
300 | * @paddr: system physical address | |
301 | * | |
302 | * Map @paddr into 64-bit bus space of the CA associated with @pcidev_info. | |
303 | * | |
304 | * The CA agp 48 bit direct address falls out as follows: | |
305 | * | |
306 | * When direct mapping AGP addresses, the 48 bit AGP address is | |
307 | * constructed as follows: | |
308 | * | |
309 | * [47:40] - Low 8 bits of the page Node ID extracted from coretalk | |
310 | * address [47:40]. The upper 8 node bits are fixed | |
311 | * and come from the xxx register bits [5:0] | |
312 | * [39:38] - Chiplet ID extracted from coretalk address [39:38] | |
313 | * [37:00] - node offset extracted from coretalk address [37:00] | |
314 | * | |
315 | * Since the node id in general will be non-zero, and the chiplet id | |
316 | * will always be non-zero, it follows that the device must support | |
317 | * a dma mask of at least 0xffffffffff (40 bits) to target node 0 | |
318 | * and in general should be 0xffffffffffff (48 bits) to target nodes | |
319 | * up to 255. Nodes above 255 need the support of the xxx register, | |
320 | * and so a given CA can only directly target nodes in the range | |
321 | * xxx - xxx+255. | |
322 | */ | |
53493dcf PB |
323 | static u64 |
324 | tioca_dma_d48(struct pci_dev *pdev, u64 paddr) | |
9c90bdde MM |
325 | { |
326 | struct tioca_common *tioca_common; | |
b3e5b5b2 | 327 | struct tioca __iomem *ca_base; |
53493dcf | 328 | u64 ct_addr; |
9c90bdde | 329 | dma_addr_t bus_addr; |
53493dcf PB |
330 | u32 node_upper; |
331 | u64 agp_dma_extn; | |
9c90bdde MM |
332 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); |
333 | ||
334 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | |
b3e5b5b2 | 335 | ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base; |
9c90bdde MM |
336 | |
337 | ct_addr = PHYS_TO_TIODMA(paddr); | |
338 | if (!ct_addr) | |
339 | return 0; | |
340 | ||
92a582ed | 341 | bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffffUL); |
9c90bdde MM |
342 | node_upper = ct_addr >> 48; |
343 | ||
344 | if (node_upper > 64) { | |
345 | printk(KERN_ERR "%s: coretalk addr 0x%p node id out " | |
d4ed8084 | 346 | "of range\n", __func__, (void *)ct_addr); |
9c90bdde MM |
347 | return 0; |
348 | } | |
349 | ||
5fbcf9a5 | 350 | agp_dma_extn = __sn_readq_relaxed(&ca_base->ca_agp_dma_addr_extn); |
9c90bdde MM |
351 | if (node_upper != (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)) { |
352 | printk(KERN_ERR "%s: coretalk upper node (%u) " | |
e088a4ad | 353 | "mismatch with ca_agp_dma_addr_extn (%llu)\n", |
d4ed8084 | 354 | __func__, |
9c90bdde MM |
355 | node_upper, (agp_dma_extn >> CA_AGP_DMA_NODE_ID_SHFT)); |
356 | return 0; | |
357 | } | |
358 | ||
359 | return bus_addr; | |
360 | } | |
361 | ||
362 | /** | |
363 | * tioca_dma_mapped - create a DMA mapping using a CA GART | |
364 | * @pdev: linux pci_dev representing the function | |
365 | * @paddr: host physical address to map | |
366 | * @req_size: len (bytes) to map | |
367 | * | |
368 | * Map @paddr into CA address space using the GART mechanism. The mapped | |
72fdbdce | 369 | * dma_addr_t is guaranteed to be contiguous in CA bus space. |
9c90bdde MM |
370 | */ |
371 | static dma_addr_t | |
e088a4ad | 372 | tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size) |
9c90bdde | 373 | { |
81f6527b | 374 | int ps, ps_shift, entry, entries, mapsize; |
53493dcf | 375 | u64 xio_addr, end_xio_addr; |
9c90bdde MM |
376 | struct tioca_common *tioca_common; |
377 | struct tioca_kernel *tioca_kern; | |
378 | dma_addr_t bus_addr = 0; | |
379 | struct tioca_dmamap *ca_dmamap; | |
380 | void *map; | |
381 | unsigned long flags; | |
53b3531b | 382 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); |
9c90bdde MM |
383 | |
384 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | |
385 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; | |
386 | ||
387 | xio_addr = PHYS_TO_TIODMA(paddr); | |
388 | if (!xio_addr) | |
389 | return 0; | |
390 | ||
391 | spin_lock_irqsave(&tioca_kern->ca_lock, flags); | |
392 | ||
393 | /* | |
394 | * allocate a map struct | |
395 | */ | |
396 | ||
f96cb1f0 | 397 | ca_dmamap = kzalloc(sizeof(struct tioca_dmamap), GFP_ATOMIC); |
9c90bdde MM |
398 | if (!ca_dmamap) |
399 | goto map_return; | |
400 | ||
401 | /* | |
402 | * Locate free entries that can hold req_size. Account for | |
403 | * unaligned start/length when allocating. | |
404 | */ | |
405 | ||
406 | ps = tioca_kern->ca_ap_pagesize; /* will be power of 2 */ | |
407 | ps_shift = ffs(ps) - 1; | |
408 | end_xio_addr = xio_addr + req_size - 1; | |
409 | ||
410 | entries = (end_xio_addr >> ps_shift) - (xio_addr >> ps_shift) + 1; | |
411 | ||
412 | map = tioca_kern->ca_pcigart_pagemap; | |
413 | mapsize = tioca_kern->ca_pcigart_entries; | |
414 | ||
81f6527b AM |
415 | entry = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0); |
416 | if (entry >= mapsize) { | |
6bf6a1a4 | 417 | kfree(ca_dmamap); |
9c90bdde | 418 | goto map_return; |
6bf6a1a4 | 419 | } |
9c90bdde | 420 | |
81f6527b | 421 | bitmap_set(map, entry, entries); |
9c90bdde MM |
422 | |
423 | bus_addr = tioca_kern->ca_pciap_base + (entry * ps); | |
424 | ||
425 | ca_dmamap->cad_dma_addr = bus_addr; | |
426 | ca_dmamap->cad_gart_size = entries; | |
427 | ca_dmamap->cad_gart_entry = entry; | |
3ea8b477 | 428 | list_add(&ca_dmamap->cad_list, &tioca_kern->ca_dmamaps); |
9c90bdde MM |
429 | |
430 | if (xio_addr % ps) { | |
431 | tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); | |
432 | bus_addr += xio_addr & (ps - 1); | |
433 | xio_addr &= ~(ps - 1); | |
434 | xio_addr += ps; | |
435 | entry++; | |
436 | } | |
437 | ||
438 | while (xio_addr < end_xio_addr) { | |
439 | tioca_kern->ca_pcigart[entry] = tioca_paddr_to_gart(xio_addr); | |
440 | xio_addr += ps; | |
441 | entry++; | |
442 | } | |
443 | ||
444 | tioca_tlbflush(tioca_kern); | |
445 | ||
446 | map_return: | |
447 | spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); | |
448 | return bus_addr; | |
449 | } | |
450 | ||
451 | /** | |
452 | * tioca_dma_unmap - release CA mapping resources | |
453 | * @pdev: linux pci_dev representing the function | |
454 | * @bus_addr: bus address returned by an earlier tioca_dma_map | |
455 | * @dir: mapping direction (unused) | |
456 | * | |
457 | * Locate mapping resources associated with @bus_addr and release them. | |
458 | * For mappings created using the direct modes (64 or 48) there are no | |
459 | * resources to release. | |
460 | */ | |
92a582ed | 461 | static void |
9c90bdde MM |
462 | tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) |
463 | { | |
464 | int i, entry; | |
465 | struct tioca_common *tioca_common; | |
466 | struct tioca_kernel *tioca_kern; | |
467 | struct tioca_dmamap *map; | |
468 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(pdev); | |
469 | unsigned long flags; | |
470 | ||
471 | tioca_common = (struct tioca_common *)pcidev_info->pdi_pcibus_info; | |
472 | tioca_kern = (struct tioca_kernel *)tioca_common->ca_kernel_private; | |
473 | ||
474 | /* return straight away if this isn't be a mapped address */ | |
475 | ||
476 | if (bus_addr < tioca_kern->ca_pciap_base || | |
477 | bus_addr >= (tioca_kern->ca_pciap_base + tioca_kern->ca_pciap_size)) | |
478 | return; | |
479 | ||
480 | spin_lock_irqsave(&tioca_kern->ca_lock, flags); | |
481 | ||
482 | list_for_each_entry(map, &tioca_kern->ca_dmamaps, cad_list) | |
483 | if (map->cad_dma_addr == bus_addr) | |
484 | break; | |
485 | ||
486 | BUG_ON(map == NULL); | |
487 | ||
488 | entry = map->cad_gart_entry; | |
489 | ||
490 | for (i = 0; i < map->cad_gart_size; i++, entry++) { | |
491 | clear_bit(entry, tioca_kern->ca_pcigart_pagemap); | |
492 | tioca_kern->ca_pcigart[entry] = 0; | |
493 | } | |
494 | tioca_tlbflush(tioca_kern); | |
495 | ||
496 | list_del(&map->cad_list); | |
497 | spin_unlock_irqrestore(&tioca_kern->ca_lock, flags); | |
498 | kfree(map); | |
499 | } | |
500 | ||
501 | /** | |
502 | * tioca_dma_map - map pages for PCI DMA | |
503 | * @pdev: linux pci_dev representing the function | |
504 | * @paddr: host physical address to map | |
505 | * @byte_count: bytes to map | |
506 | * | |
507 | * This is the main wrapper for mapping host physical pages to CA PCI space. | |
508 | * The mapping mode used is based on the devices dma_mask. As a last resort | |
509 | * use the GART mapped mode. | |
510 | */ | |
53493dcf | 511 | static u64 |
83821d3f | 512 | tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) |
9c90bdde | 513 | { |
53493dcf | 514 | u64 mapaddr; |
9c90bdde | 515 | |
83821d3f MM |
516 | /* |
517 | * Not supported for now ... | |
518 | */ | |
519 | if (dma_flags & SN_DMA_MSI) | |
520 | return 0; | |
521 | ||
9c90bdde | 522 | /* |
72fdbdce | 523 | * If card is 64 or 48 bit addressable, use a direct mapping. 32 |
9c90bdde MM |
524 | * bit direct is so restrictive w.r.t. where the memory resides that |
525 | * we don't use it even though CA has some support. | |
526 | */ | |
527 | ||
528 | if (pdev->dma_mask == ~0UL) | |
529 | mapaddr = tioca_dma_d64(paddr); | |
530 | else if (pdev->dma_mask == 0xffffffffffffUL) | |
531 | mapaddr = tioca_dma_d48(pdev, paddr); | |
532 | else | |
533 | mapaddr = 0; | |
534 | ||
535 | /* Last resort ... use PCI portion of CA GART */ | |
536 | ||
537 | if (mapaddr == 0) | |
538 | mapaddr = tioca_dma_mapped(pdev, paddr, byte_count); | |
539 | ||
540 | return mapaddr; | |
541 | } | |
542 | ||
543 | /** | |
544 | * tioca_error_intr_handler - SGI TIO CA error interrupt handler | |
545 | * @irq: unused | |
546 | * @arg: pointer to tioca_common struct for the given CA | |
9c90bdde MM |
547 | * |
548 | * Handle a CA error interrupt. Simply a wrapper around a SAL call which | |
549 | * defers processing to the SGI prom. | |
550 | */ | |
551 | static irqreturn_t | |
7d12e780 | 552 | tioca_error_intr_handler(int irq, void *arg) |
9c90bdde MM |
553 | { |
554 | struct tioca_common *soft = arg; | |
555 | struct ia64_sal_retval ret_stuff; | |
53493dcf PB |
556 | u64 segment; |
557 | u64 busnum; | |
9c90bdde MM |
558 | ret_stuff.status = 0; |
559 | ret_stuff.v0 = 0; | |
560 | ||
674c6479 | 561 | segment = soft->ca_common.bs_persist_segment; |
9c90bdde MM |
562 | busnum = soft->ca_common.bs_persist_busnum; |
563 | ||
564 | SAL_CALL_NOLOCK(ret_stuff, | |
565 | (u64) SN_SAL_IOIF_ERROR_INTERRUPT, | |
566 | segment, busnum, 0, 0, 0, 0, 0); | |
567 | ||
568 | return IRQ_HANDLED; | |
569 | } | |
570 | ||
571 | /** | |
572 | * tioca_bus_fixup - perform final PCI fixup for a TIO CA bus | |
573 | * @prom_bussoft: Common prom/kernel struct representing the bus | |
574 | * | |
575 | * Replicates the tioca_common pointed to by @prom_bussoft in kernel | |
576 | * space. Allocates and initializes a kernel-only area for a given CA, | |
577 | * and sets up an irq for handling CA error interrupts. | |
578 | * | |
579 | * On successful setup, returns the kernel version of tioca_common back to | |
580 | * the caller. | |
581 | */ | |
92a582ed | 582 | static void * |
7c2a6c62 | 583 | tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) |
9c90bdde MM |
584 | { |
585 | struct tioca_common *tioca_common; | |
586 | struct tioca_kernel *tioca_kern; | |
587 | struct pci_bus *bus; | |
588 | ||
589 | /* sanity check prom rev */ | |
590 | ||
d3e5e1a1 | 591 | if (is_shub1() && sn_sal_rev() < 0x0406) { |
9c90bdde MM |
592 | printk |
593 | (KERN_ERR "%s: SGI prom rev 4.06 or greater required " | |
d4ed8084 | 594 | "for tioca support\n", __func__); |
9c90bdde MM |
595 | return NULL; |
596 | } | |
597 | ||
598 | /* | |
599 | * Allocate kernel bus soft and copy from prom. | |
600 | */ | |
601 | ||
f96cb1f0 | 602 | tioca_common = kzalloc(sizeof(struct tioca_common), GFP_KERNEL); |
9c90bdde MM |
603 | if (!tioca_common) |
604 | return NULL; | |
605 | ||
606 | memcpy(tioca_common, prom_bussoft, sizeof(struct tioca_common)); | |
1ee27a4e JS |
607 | tioca_common->ca_common.bs_base = (unsigned long) |
608 | ioremap(REGION_OFFSET(tioca_common->ca_common.bs_base), | |
609 | sizeof(struct tioca_common)); | |
9c90bdde MM |
610 | |
611 | /* init kernel-private area */ | |
612 | ||
f96cb1f0 | 613 | tioca_kern = kzalloc(sizeof(struct tioca_kernel), GFP_KERNEL); |
9c90bdde MM |
614 | if (!tioca_kern) { |
615 | kfree(tioca_common); | |
616 | return NULL; | |
617 | } | |
618 | ||
619 | tioca_kern->ca_common = tioca_common; | |
620 | spin_lock_init(&tioca_kern->ca_lock); | |
621 | INIT_LIST_HEAD(&tioca_kern->ca_dmamaps); | |
622 | tioca_kern->ca_closest_node = | |
623 | nasid_to_cnodeid(tioca_common->ca_closest_nasid); | |
53493dcf | 624 | tioca_common->ca_kernel_private = (u64) tioca_kern; |
9c90bdde | 625 | |
674c6479 CN |
626 | bus = pci_find_bus(tioca_common->ca_common.bs_persist_segment, |
627 | tioca_common->ca_common.bs_persist_busnum); | |
9c90bdde MM |
628 | BUG_ON(!bus); |
629 | tioca_kern->ca_devices = &bus->devices; | |
630 | ||
631 | /* init GART */ | |
632 | ||
633 | if (tioca_gart_init(tioca_kern) < 0) { | |
634 | kfree(tioca_kern); | |
635 | kfree(tioca_common); | |
636 | return NULL; | |
637 | } | |
638 | ||
639 | tioca_gart_found++; | |
640 | list_add(&tioca_kern->ca_list, &tioca_list); | |
641 | ||
642 | if (request_irq(SGI_TIOCA_ERROR, | |
643 | tioca_error_intr_handler, | |
121a4226 | 644 | IRQF_SHARED, "TIOCA error", (void *)tioca_common)) |
9c90bdde MM |
645 | printk(KERN_WARNING |
646 | "%s: Unable to get irq %d. " | |
647 | "Error interrupts won't be routed for TIOCA bus %d\n", | |
d4ed8084 | 648 | __func__, SGI_TIOCA_ERROR, |
9c90bdde MM |
649 | (int)tioca_common->ca_common.bs_persist_busnum); |
650 | ||
6e9de181 JK |
651 | sn_set_err_irq_affinity(SGI_TIOCA_ERROR); |
652 | ||
7c2a6c62 CL |
653 | /* Setup locality information */ |
654 | controller->node = tioca_kern->ca_closest_node; | |
9c90bdde MM |
655 | return tioca_common; |
656 | } | |
657 | ||
658 | static struct sn_pcibus_provider tioca_pci_interfaces = { | |
659 | .dma_map = tioca_dma_map, | |
660 | .dma_map_consistent = tioca_dma_map, | |
661 | .dma_unmap = tioca_dma_unmap, | |
662 | .bus_fixup = tioca_bus_fixup, | |
8409668b MM |
663 | .force_interrupt = NULL, |
664 | .target_interrupt = NULL | |
9c90bdde MM |
665 | }; |
666 | ||
667 | /** | |
668 | * tioca_init_provider - init SN PCI provider ops for TIO CA | |
669 | */ | |
670 | int | |
671 | tioca_init_provider(void) | |
672 | { | |
673 | sn_pci_provider[PCIIO_ASIC_TYPE_TIOCA] = &tioca_pci_interfaces; | |
674 | return 0; | |
675 | } |