PageRenderTime 44ms CodeModel.GetById 18ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/ia64/sn/pci/pcibr/pcibr_ate.c

https://bitbucket.org/evzijst/gittest
C | 188 lines | 114 code | 31 blank | 43 comment | 17 complexity | c2b40f97c04cd1e9f8f056ba7d7e79bb 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) 2001-2004 Silicon Graphics, Inc. All rights reserved.
  7 */
  8
  9#include <linux/types.h>
 10#include <asm/sn/sn_sal.h>
 11#include "pci/pcibus_provider_defs.h"
 12#include "pci/pcidev.h"
 13#include "pci/pcibr_provider.h"
 14
 15int pcibr_invalidate_ate = 0;	/* by default don't invalidate ATE on free */
 16
 17/*
 18 * mark_ate: Mark the ate as either free or inuse.
 19 */
 20static void mark_ate(struct ate_resource *ate_resource, int start, int number,
 21		     uint64_t value)
 22{
 23
 24	uint64_t *ate = ate_resource->ate;
 25	int index;
 26	int length = 0;
 27
 28	for (index = start; length < number; index++, length++)
 29		ate[index] = value;
 30
 31}
 32
 33/*
 34 * find_free_ate:  Find the first free ate index starting from the given
 35 *		   index for the desired consequtive count.
 36 */
 37static int find_free_ate(struct ate_resource *ate_resource, int start,
 38			 int count)
 39{
 40
 41	uint64_t *ate = ate_resource->ate;
 42	int index;
 43	int start_free;
 44
 45	for (index = start; index < ate_resource->num_ate;) {
 46		if (!ate[index]) {
 47			int i;
 48			int free;
 49			free = 0;
 50			start_free = index;	/* Found start free ate */
 51			for (i = start_free; i < ate_resource->num_ate; i++) {
 52				if (!ate[i]) {	/* This is free */
 53					if (++free == count)
 54						return start_free;
 55				} else {
 56					index = i + 1;
 57					break;
 58				}
 59			}
 60		} else
 61			index++;	/* Try next ate */
 62	}
 63
 64	return -1;
 65}
 66
 67/*
 68 * free_ate_resource:  Free the requested number of ATEs.
 69 */
 70static inline void free_ate_resource(struct ate_resource *ate_resource,
 71				     int start)
 72{
 73
 74	mark_ate(ate_resource, start, ate_resource->ate[start], 0);
 75	if ((ate_resource->lowest_free_index > start) ||
 76	    (ate_resource->lowest_free_index < 0))
 77		ate_resource->lowest_free_index = start;
 78
 79}
 80
 81/*
 82 * alloc_ate_resource:  Allocate the requested number of ATEs.
 83 */
 84static inline int alloc_ate_resource(struct ate_resource *ate_resource,
 85				     int ate_needed)
 86{
 87
 88	int start_index;
 89
 90	/*
 91	 * Check for ate exhaustion.
 92	 */
 93	if (ate_resource->lowest_free_index < 0)
 94		return -1;
 95
 96	/*
 97	 * Find the required number of free consequtive ates.
 98	 */
 99	start_index =
100	    find_free_ate(ate_resource, ate_resource->lowest_free_index,
101			  ate_needed);
102	if (start_index >= 0)
103		mark_ate(ate_resource, start_index, ate_needed, ate_needed);
104
105	ate_resource->lowest_free_index =
106	    find_free_ate(ate_resource, ate_resource->lowest_free_index, 1);
107
108	return start_index;
109}
110
111/*
112 * Allocate "count" contiguous Bridge Address Translation Entries
113 * on the specified bridge to be used for PCI to XTALK mappings.
114 * Indices in rm map range from 1..num_entries.  Indicies returned
115 * to caller range from 0..num_entries-1.
116 *
117 * Return the start index on success, -1 on failure.
118 */
119int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count)
120{
121	int status = 0;
122	uint64_t flag;
123
124	flag = pcibr_lock(pcibus_info);
125	status = alloc_ate_resource(&pcibus_info->pbi_int_ate_resource, count);
126
127	if (status < 0) {
128		/* Failed to allocate */
129		pcibr_unlock(pcibus_info, flag);
130		return -1;
131	}
132
133	pcibr_unlock(pcibus_info, flag);
134
135	return status;
136}
137
138/*
139 * Setup an Address Translation Entry as specified.  Use either the Bridge
140 * internal maps or the external map RAM, as appropriate.
141 */
142static inline uint64_t *pcibr_ate_addr(struct pcibus_info *pcibus_info,
143				       int ate_index)
144{
145	if (ate_index < pcibus_info->pbi_int_ate_size) {
146		return pcireg_int_ate_addr(pcibus_info, ate_index);
147	}
148	panic("pcibr_ate_addr: invalid ate_index 0x%x", ate_index);
149}
150
151/*
152 * Update the ate.
153 */
154void inline
155ate_write(struct pcibus_info *pcibus_info, int ate_index, int count,
156	  volatile uint64_t ate)
157{
158	while (count-- > 0) {
159		if (ate_index < pcibus_info->pbi_int_ate_size) {
160			pcireg_int_ate_set(pcibus_info, ate_index, ate);
161		} else {
162			panic("ate_write: invalid ate_index 0x%x", ate_index);
163		}
164		ate_index++;
165		ate += IOPGSIZE;
166	}
167
168	pcireg_tflush_get(pcibus_info);	/* wait until Bridge PIO complete */
169}
170
171void pcibr_ate_free(struct pcibus_info *pcibus_info, int index)
172{
173
174	volatile uint64_t ate;
175	int count;
176	uint64_t flags;
177
178	if (pcibr_invalidate_ate) {
179		/* For debugging purposes, clear the valid bit in the ATE */
180		ate = *pcibr_ate_addr(pcibus_info, index);
181		count = pcibus_info->pbi_int_ate_resource.ate[index];
182		ate_write(pcibus_info, index, count, (ate & ~PCI32_ATE_V));
183	}
184
185	flags = pcibr_lock(pcibus_info);
186	free_ate_resource(&pcibus_info->pbi_int_ate_resource, index);
187	pcibr_unlock(pcibus_info, flags);
188}