1 /*
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
8  */
9 
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/module.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/sn_cpuid.h>
15 #include <asm/sn/addrs.h>
16 #include <asm/sn/arch.h>
17 #include <asm/sn/iograph.h>
18 #include <asm/sn/invent.h>
19 #include <asm/sn/hcl.h>
20 #include <asm/sn/labelcl.h>
21 #include <asm/sn/xtalk/xwidget.h>
22 #include <asm/sn/pci/bridge.h>
23 #include <asm/sn/pci/pciio.h>
24 #include <asm/sn/pci/pcibr.h>
25 #include <asm/sn/pci/pcibr_private.h>
26 #include <asm/sn/pci/pci_defs.h>
27 #include <asm/sn/prio.h>
28 #include <asm/sn/xtalk/xbow.h>
29 #include <asm/sn/ioc3.h>
30 #include <asm/sn/io.h>
31 #include <asm/sn/sn_private.h>
32 
33 #ifndef LOCAL
34 #define LOCAL           static
35 #endif
36 
37 /*
38  * functions
39  */
40 int               pcibr_init_ext_ate_ram(bridge_t *);
41 int               pcibr_ate_alloc(pcibr_soft_t, int);
42 void              pcibr_ate_free(pcibr_soft_t, int, int);
43 bridge_ate_t      pcibr_flags_to_ate(unsigned);
44 bridge_ate_p      pcibr_ate_addr(pcibr_soft_t, int);
45 unsigned 	  ate_freeze(pcibr_dmamap_t pcibr_dmamap,
46 #if PCIBR_FREEZE_TIME
47 	   			unsigned *freeze_time_ptr,
48 #endif
49 	   			unsigned *cmd_regs);
50 void 	  ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
51 void ate_thaw(pcibr_dmamap_t pcibr_dmamap,
52 	 			int ate_index,
53 #if PCIBR_FREEZE_TIME
54 	 			bridge_ate_t ate,
55 	 			int ate_total,
56 	 			unsigned freeze_time_start,
57 #endif
58 	 			unsigned *cmd_regs,
59 	 			unsigned s);
60 
61 
62 /* Convert from ssram_bits in control register to number of SSRAM entries */
63 #define ATE_NUM_ENTRIES(n) _ate_info[n]
64 
65 /* Possible choices for number of ATE entries in Bridge's SSRAM */
66 LOCAL int               _ate_info[] =
67 {
68     0,					/* 0 entries */
69     8 * 1024,				/* 8K entries */
70     16 * 1024,				/* 16K entries */
71     64 * 1024				/* 64K entries */
72 };
73 
74 #define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int))
75 #define ATE_PROBE_VALUE 0x0123456789abcdefULL
76 
77 /*
78  * Determine the size of this bridge's external mapping SSRAM, and set
79  * the control register appropriately to reflect this size, and initialize
80  * the external SSRAM.
81  */
82 int
pcibr_init_ext_ate_ram(bridge_t * bridge)83 pcibr_init_ext_ate_ram(bridge_t *bridge)
84 {
85     int                     largest_working_size = 0;
86     int                     num_entries, entry;
87     int                     i, j;
88     bridgereg_t             old_enable, new_enable;
89 
90     /* Probe SSRAM to determine its size. */
91     old_enable = bridge->b_int_enable;
92     new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
93     bridge->b_int_enable = new_enable;
94 
95     for (i = 1; i < ATE_NUM_SIZES; i++) {
96 	/* Try writing a value */
97 	bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
98 
99 	/* Guard against wrap */
100 	for (j = 1; j < i; j++)
101 	    bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0;
102 
103 	/* See if value was written */
104 	if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
105 				largest_working_size = i;
106     }
107     bridge->b_int_enable = old_enable;
108     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
109 
110     /*
111      * ensure that we write and read without any interruption.
112      * The read following the write is required for the Bridge war
113      */
114 
115     bridge->b_wid_control = (bridge->b_wid_control
116 			& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
117 			| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
118     bridge->b_wid_control;		/* inval addr bug war */
119 
120     num_entries = ATE_NUM_ENTRIES(largest_working_size);
121 
122     if (pcibr_debug_mask & PCIBR_DEBUG_ATE) {
123 	if (num_entries) {
124 	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
125 			"bridge at 0x%x: clearing %d external ATEs\n",
126 			bridge, num_entries));
127 	} else {
128 	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
129 			"bridge at 0x%x: no external ATE RAM found\n",
130 			bridge));
131 	}
132     }
133 
134     /* Initialize external mapping entries */
135     for (entry = 0; entry < num_entries; entry++)
136 	bridge->b_ext_ate_ram[entry] = 0;
137 
138     return (num_entries);
139 }
140 
141 /*
142  * Allocate "count" contiguous Bridge Address Translation Entries
143  * on the specified bridge to be used for PCI to XTALK mappings.
144  * Indices in rm map range from 1..num_entries.  Indicies returned
145  * to caller range from 0..num_entries-1.
146  *
147  * Return the start index on success, -1 on failure.
148  */
149 int
pcibr_ate_alloc(pcibr_soft_t pcibr_soft,int count)150 pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count)
151 {
152     int			    status = 0;
153     struct resource	    *new_res;
154     struct resource         **allocated_res;
155 
156     new_res = (struct resource *) kmalloc( sizeof(struct resource), GFP_ATOMIC);
157     memset(new_res, 0, sizeof(*new_res));
158     status = allocate_resource( &pcibr_soft->bs_int_ate_resource, new_res,
159 				count, pcibr_soft->bs_int_ate_resource.start,
160 				pcibr_soft->bs_int_ate_resource.end, 1,
161 				NULL, NULL);
162 
163     if ( status && (pcibr_soft->bs_ext_ate_resource.end != 0) ) {
164 	status = allocate_resource( &pcibr_soft->bs_ext_ate_resource, new_res,
165 				count, pcibr_soft->bs_ext_ate_resource.start,
166 				pcibr_soft->bs_ext_ate_resource.end, 1,
167 				NULL, NULL);
168 	if (status) {
169 		new_res->start = -1;
170 	}
171     }
172 
173     if (status) {
174 	/* Failed to allocate */
175 	kfree(new_res);
176 	return -1;
177     }
178 
179     /* Save the resource for freeing */
180     allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + new_res->start * sizeof( unsigned long));
181     *allocated_res = new_res;
182 
183     return new_res->start;
184 }
185 
186 void
pcibr_ate_free(pcibr_soft_t pcibr_soft,int index,int count)187 pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count)
188 /* Who says there's no such thing as a free meal? :-) */
189 {
190 
191     struct resource **allocated_res;
192     int status = 0;
193 
194     allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + index * sizeof(unsigned long));
195 
196     status = release_resource(*allocated_res);
197     if (status)
198 	BUG(); /* Ouch .. */
199     kfree(*allocated_res);
200 
201 }
202 
203 /*
204  * Convert PCI-generic software flags and Bridge-specific software flags
205  * into Bridge-specific Address Translation Entry attribute bits.
206  */
207 bridge_ate_t
pcibr_flags_to_ate(unsigned flags)208 pcibr_flags_to_ate(unsigned flags)
209 {
210     bridge_ate_t            attributes;
211 
212     /* default if nothing specified:
213      * NOBARRIER
214      * NOPREFETCH
215      * NOPRECISE
216      * COHERENT
217      * Plus the valid bit
218      */
219     attributes = ATE_CO | ATE_V;
220 
221     /* Generic macro flags
222      */
223     if (flags & PCIIO_DMA_DATA) {	/* standard data channel */
224 	attributes &= ~ATE_BAR;		/* no barrier */
225 	attributes |= ATE_PREF;		/* prefetch on */
226     }
227     if (flags & PCIIO_DMA_CMD) {	/* standard command channel */
228 	attributes |= ATE_BAR;		/* barrier bit on */
229 	attributes &= ~ATE_PREF;	/* disable prefetch */
230     }
231     /* Generic detail flags
232      */
233     if (flags & PCIIO_PREFETCH)
234 	attributes |= ATE_PREF;
235     if (flags & PCIIO_NOPREFETCH)
236 	attributes &= ~ATE_PREF;
237 
238     /* Provider-specific flags
239      */
240     if (flags & PCIBR_BARRIER)
241 	attributes |= ATE_BAR;
242     if (flags & PCIBR_NOBARRIER)
243 	attributes &= ~ATE_BAR;
244 
245     if (flags & PCIBR_PREFETCH)
246 	attributes |= ATE_PREF;
247     if (flags & PCIBR_NOPREFETCH)
248 	attributes &= ~ATE_PREF;
249 
250     if (flags & PCIBR_PRECISE)
251 	attributes |= ATE_PREC;
252     if (flags & PCIBR_NOPRECISE)
253 	attributes &= ~ATE_PREC;
254 
255     return (attributes);
256 }
257 
258 /*
259  * Setup an Address Translation Entry as specified.  Use either the Bridge
260  * internal maps or the external map RAM, as appropriate.
261  */
262 bridge_ate_p
pcibr_ate_addr(pcibr_soft_t pcibr_soft,int ate_index)263 pcibr_ate_addr(pcibr_soft_t pcibr_soft,
264 	       int ate_index)
265 {
266     bridge_t *bridge = pcibr_soft->bs_base;
267 
268     return (ate_index < pcibr_soft->bs_int_ate_size)
269 	? &(bridge->b_int_ate_ram[ate_index].wr)
270 	: &(bridge->b_ext_ate_ram[ate_index]);
271 }
272 
273 /* We are starting to get more complexity
274  * surrounding writing ATEs, so pull
275  * the writing code into this new function.
276  */
277 
278 #if PCIBR_FREEZE_TIME
279 #define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs)
280 #else
281 #define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, cmd_regs)
282 #endif
283 
284 unsigned
ate_freeze(pcibr_dmamap_t pcibr_dmamap,unsigned * freeze_time_ptr,unsigned * cmd_regs)285 ate_freeze(pcibr_dmamap_t pcibr_dmamap,
286 #if PCIBR_FREEZE_TIME
287 	   unsigned *freeze_time_ptr,
288 #endif
289 	   unsigned *cmd_regs)
290 {
291     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
292 #ifdef LATER
293     int                     dma_slot = pcibr_dmamap->bd_slot;
294 #endif
295     int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;
296     int                     slot;
297 
298     unsigned long           s;
299     unsigned                cmd_reg;
300     volatile unsigned      *cmd_lwa;
301     unsigned                cmd_lwd;
302 
303     if (!ext_ates)
304 	return 0;
305 
306     /* Bridge Hardware Bug WAR #484930:
307      * Bridge can't handle updating External ATEs
308      * while DMA is occurring that uses External ATEs,
309      * even if the particular ATEs involved are disjoint.
310      */
311 
312     /* need to prevent anyone else from
313      * unfreezing the grant while we
314      * are working; also need to prevent
315      * this thread from being interrupted
316      * to keep PCI grant freeze time
317      * at an absolute minimum.
318      */
319     s = pcibr_lock(pcibr_soft);
320 
321 #ifdef LATER
322     /* just in case pcibr_dmamap_done was not called */
323     if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) {
324 	pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY;
325 	if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM)
326 	    atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
327 	xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);
328     }
329 #endif	/* LATER */
330 #if PCIBR_FREEZE_TIME
331     *freeze_time_ptr = get_timestamp();
332 #endif
333 
334     cmd_lwa = 0;
335     for (slot = pcibr_soft->bs_min_slot;
336 		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
337 	if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
338 	    cmd_reg = pcibr_soft->
339 		bs_slot[slot].
340 		bss_cmd_shadow;
341 	    if (cmd_reg & PCI_CMD_BUS_MASTER) {
342 		cmd_lwa = pcibr_soft->
343 		    bs_slot[slot].
344 		    bss_cmd_pointer;
345 		cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER;
346 		cmd_lwa[0] = cmd_lwd;
347 	    }
348 	    cmd_regs[slot] = cmd_reg;
349 	} else
350 	    cmd_regs[slot] = 0;
351 
352     if (cmd_lwa) {
353 	    bridge_t	*bridge = pcibr_soft->bs_base;
354 
355 	    /* Read the last master bit that has been cleared. This PIO read
356 	     * on the PCI bus is to ensure the completion of any DMAs that
357 	     * are due to bus requests issued by PCI devices before the
358 	     * clearing of master bits.
359 	     */
360 	    cmd_lwa[0];
361 
362 	    /* Flush all the write buffers in the bridge */
363 	    for (slot = pcibr_soft->bs_min_slot;
364 				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
365 		    if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
366 			    /* Flush the write buffer associated with this
367 			     * PCI device which might be using dma map RAM.
368 			     */
369 			bridge->b_wr_req_buf[slot].reg;
370 		    }
371 	    }
372     }
373     return s;
374 }
375 
376 void
ate_write(pcibr_soft_t pcibr_soft,bridge_ate_p ate_ptr,int ate_count,bridge_ate_t ate)377 ate_write(pcibr_soft_t pcibr_soft,
378 	  bridge_ate_p ate_ptr,
379 	  int ate_count,
380 	  bridge_ate_t ate)
381 {
382     	while (ate_count-- > 0) {
383 		*ate_ptr++ = ate;
384 		ate += IOPGSIZE;
385 	}
386 }
387 
388 #if PCIBR_FREEZE_TIME
389 #define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s)
390 #else
391 #define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s)
392 #endif
393 
394 void
ate_thaw(pcibr_dmamap_t pcibr_dmamap,int ate_index,bridge_ate_t ate,int ate_total,unsigned freeze_time_start,unsigned * cmd_regs,unsigned s)395 ate_thaw(pcibr_dmamap_t pcibr_dmamap,
396 	 int ate_index,
397 #if PCIBR_FREEZE_TIME
398 	 bridge_ate_t ate,
399 	 int ate_total,
400 	 unsigned freeze_time_start,
401 #endif
402 	 unsigned *cmd_regs,
403 	 unsigned s)
404 {
405     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
406     int                     dma_slot = pcibr_dmamap->bd_slot;
407     int                     slot;
408     bridge_t               *bridge = pcibr_soft->bs_base;
409     int                     ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM;
410 
411     unsigned                cmd_reg;
412 
413 #if PCIBR_FREEZE_TIME
414     unsigned                freeze_time;
415     static unsigned         max_freeze_time = 0;
416     static unsigned         max_ate_total;
417 #endif
418 
419     if (!ext_ates)
420 	return;
421 
422     /* restore cmd regs */
423     for (slot = pcibr_soft->bs_min_slot;
424 		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
425 	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) {
426 		pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);
427 	}
428     }
429     pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY;
430     atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
431 
432 #if PCIBR_FREEZE_TIME
433     freeze_time = get_timestamp() - freeze_time_start;
434 
435     if ((max_freeze_time < freeze_time) ||
436 	(max_ate_total < ate_total)) {
437 	if (max_freeze_time < freeze_time)
438 	    max_freeze_time = freeze_time;
439 	if (max_ate_total < ate_total)
440 	    max_ate_total = ate_total;
441 	pcibr_unlock(pcibr_soft, s);
442 	printk( "%s: pci freeze time %d usec for %d ATEs\n"
443 		"\tfirst ate: %R\n",
444 		pcibr_soft->bs_name,
445 		freeze_time * 1000 / 1250,
446 		ate_total,
447 		ate, ate_bits);
448     } else
449 #endif
450 	pcibr_unlock(pcibr_soft, s);
451 }
452