Subversion Repositories Kolibri OS

Rev

Rev 6104 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4075 Serge 1
/*
2
 * Copyright (c) Red Hat Inc.
3
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 * copy of this software and associated documentation files (the "Software"),
6
 * to deal in the Software without restriction, including without limitation
7
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8
 * and/or sell copies of the Software, and to permit persons to whom the
9
 * Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice (including the
12
 * next paragraph) shall be included in all copies or substantial portions
13
 * of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 *
23
 * Authors: Dave Airlie 
24
 *          Jerome Glisse 
25
 *          Pauli Nieminen 
26
 */
27
 
28
/* simple list based uncached page pool
29
 * - Pool collects resently freed pages for reuse
30
 * - Use page->lru to keep a free list
31
 * - doesn't track currently in use pages
32
 */
33
 
34
#define pr_fmt(fmt) "[TTM] " fmt
35
 
36
#include 
37
#include 
38
//#include 
39
//#include 
40
#include 
41
#include 
42
#include  /* for seq_printf */
43
#include 
6296 serge 44
#include 
4075 Serge 45
 
5346 serge 46
#include 
4075 Serge 47
 
48
#include 
49
#include 
50
 
51
#ifdef TTM_HAS_AGP
52
#include 
53
#endif
54
 
55
#define NUM_PAGES_TO_ALLOC		(PAGE_SIZE/sizeof(struct page *))
56
#define SMALL_ALLOCATION		16
57
#define FREE_ALL_PAGES			(~0U)
58
/* times are in msecs */
59
#define PAGE_FREE_INTERVAL		1000
60
 
61
/**
62
 * struct ttm_page_pool - Pool to reuse recently allocated uc/wc pages.
63
 *
64
 * @lock: Protects the shared pool from concurrnet access. Must be used with
65
 * irqsave/irqrestore variants because pool allocator maybe called from
66
 * delayed work.
67
 * @fill_lock: Prevent concurrent calls to fill.
68
 * @list: Pool of free uc/wc pages for fast reuse.
69
 * @gfp_flags: Flags to pass for alloc_page.
70
 * @npages: Number of pages in pool.
71
 */
72
struct ttm_page_pool {
6104 serge 73
	spinlock_t		lock;
74
	bool			fill_lock;
4075 Serge 75
	struct list_head	list;
6104 serge 76
	gfp_t			gfp_flags;
77
	unsigned		npages;
78
	char			*name;
4075 Serge 79
	unsigned long		nfrees;
80
	unsigned long		nrefills;
81
};
82
 
83
/**
84
 * Limits for the pool. They are handled without locks because only place where
85
 * they may change is in sysfs store. They won't have immediate effect anyway
86
 * so forcing serialization to access them is pointless.
87
 */
88
 
89
struct ttm_pool_opts {
90
	unsigned	alloc_size;
91
	unsigned	max_size;
92
	unsigned	small;
93
};
94
 
95
#define NUM_POOLS 4
96
 
97
/**
98
 * struct ttm_pool_manager - Holds memory pools for fst allocation
99
 *
100
 * Manager is read only object for pool code so it doesn't need locking.
101
 *
102
 * @free_interval: minimum number of jiffies between freeing pages from pool.
103
 * @page_alloc_inited: reference counting for pool allocation.
104
 * @work: Work that is used to shrink the pool. Work is only run when there is
105
 * some pages to free.
106
 * @small_allocation: Limit in number of pages what is small allocation.
107
 *
108
 * @pools: All pool objects in use.
109
 **/
110
struct ttm_pool_manager {
111
	struct kobject		kobj;
112
	struct ttm_pool_opts	options;
113
 
114
	union {
115
		struct ttm_page_pool	pools[NUM_POOLS];
116
		struct {
117
			struct ttm_page_pool	wc_pool;
118
			struct ttm_page_pool	uc_pool;
119
			struct ttm_page_pool	wc_pool_dma32;
120
			struct ttm_page_pool	uc_pool_dma32;
121
		} ;
122
	};
123
};
124
 
6296 serge 125
static void ttm_pool_kobj_release(struct kobject *kobj)
126
{
127
	struct ttm_pool_manager *m =
128
		container_of(kobj, struct ttm_pool_manager, kobj);
129
	kfree(m);
130
}
4075 Serge 131
 
132
static struct ttm_pool_manager *_manager;
133
 
134
 
135
/**
136
 * Select the right pool or requested caching state and ttm flags. */
137
static struct ttm_page_pool *ttm_get_pool(int flags,
138
		enum ttm_caching_state cstate)
139
{
140
	int pool_index;
141
 
142
	if (cstate == tt_cached)
143
		return NULL;
144
 
145
	if (cstate == tt_wc)
146
		pool_index = 0x0;
147
	else
148
		pool_index = 0x1;
149
 
150
	if (flags & TTM_PAGE_FLAG_DMA32)
151
		pool_index |= 0x2;
152
 
153
	return &_manager->pools[pool_index];
154
}
155
 
156
/* set memory back to wb and free the pages. */
157
static void ttm_pages_put(struct page *pages[], unsigned npages)
158
{
159
	unsigned i;
160
	for (i = 0; i < npages; ++i)
161
		__free_page(pages[i]);
162
}
163
 
164
static void ttm_pool_update_free_locked(struct ttm_page_pool *pool,
165
		unsigned freed_pages)
166
{
167
	pool->npages -= freed_pages;
168
	pool->nfrees += freed_pages;
169
}
170
 
171
 
172
 
173
 
174
/* Put all pages in pages list to correct pool to wait for reuse */
175
static void ttm_put_pages(struct page **pages, unsigned npages, int flags,
176
			  enum ttm_caching_state cstate)
177
{
178
	unsigned long irq_flags;
5078 serge 179
	struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
4075 Serge 180
	unsigned i;
181
 
5078 serge 182
	if (1) {
4075 Serge 183
		/* No pool for this memory type so free the pages */
184
		for (i = 0; i < npages; i++) {
185
			if (pages[i]) {
186
				__free_page(pages[i]);
187
				pages[i] = NULL;
188
			}
189
		}
190
		return;
191
	}
192
 
193
}
194
 
195
/*
196
 * On success pages list will hold count number of correctly
197
 * cached pages.
198
 */
199
static int ttm_get_pages(struct page **pages, unsigned npages, int flags,
200
			 enum ttm_caching_state cstate)
201
{
5078 serge 202
	struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
4075 Serge 203
	struct list_head plist;
204
	struct page *p = NULL;
5078 serge 205
	gfp_t gfp_flags = 0;
4075 Serge 206
	unsigned count;
207
	int r;
208
 
5078 serge 209
 
4075 Serge 210
	/* No pool for cached pages */
5078 serge 211
	if (1) {
4075 Serge 212
 
213
		for (r = 0; r < npages; ++r) {
214
			p = alloc_page(gfp_flags);
215
			if (!p) {
216
 
217
				return -ENOMEM;
218
			}
219
 
220
			pages[r] = p;
221
		}
222
		return 0;
223
	}
224
 
225
 
226
 
227
	return 0;
228
}
229
 
5078 serge 230
static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags,
4075 Serge 231
		char *name)
232
{
233
	spin_lock_init(&pool->lock);
234
	pool->fill_lock = false;
235
	INIT_LIST_HEAD(&pool->list);
236
	pool->npages = pool->nfrees = 0;
237
	pool->gfp_flags = flags;
238
	pool->name = name;
239
}
240
 
241
int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
242
{
243
	int ret;
244
 
245
	WARN_ON(_manager);
246
 
247
	_manager = kzalloc(sizeof(*_manager), GFP_KERNEL);
248
 
249
	_manager->options.max_size = max_pages;
250
	_manager->options.small = SMALL_ALLOCATION;
251
	_manager->options.alloc_size = NUM_PAGES_TO_ALLOC;
252
 
253
	return 0;
254
}
255
 
256
void ttm_page_alloc_fini(void)
257
{
258
	int i;
259
 
260
	_manager = NULL;
261
}
262
 
263
int ttm_pool_populate(struct ttm_tt *ttm)
264
{
265
	struct ttm_mem_global *mem_glob = ttm->glob->mem_glob;
266
	unsigned i;
267
	int ret;
268
 
269
	if (ttm->state != tt_unpopulated)
270
		return 0;
271
 
272
	for (i = 0; i < ttm->num_pages; ++i) {
273
		ret = ttm_get_pages(&ttm->pages[i], 1,
274
				    ttm->page_flags,
275
				    ttm->caching_state);
276
		if (ret != 0) {
277
			ttm_pool_unpopulate(ttm);
278
			return -ENOMEM;
279
		}
280
	}
281
	ttm->state = tt_unbound;
282
	return 0;
283
}
284
EXPORT_SYMBOL(ttm_pool_populate);
285
 
286
void ttm_pool_unpopulate(struct ttm_tt *ttm)
287
{
288
	unsigned i;
289
 
290
	for (i = 0; i < ttm->num_pages; ++i) {
291
		if (ttm->pages[i]) {
292
			ttm_put_pages(&ttm->pages[i], 1,
293
				      ttm->page_flags,
294
				      ttm->caching_state);
295
		}
296
	}
297
	ttm->state = tt_unpopulated;
298
}
299
EXPORT_SYMBOL(ttm_pool_unpopulate);
300