sram-alloc.c 20.8 KB
Newer Older
Bryan Wu's avatar
Bryan Wu committed
1
/*
2
 * File:         arch/blackfin/mm/sram-alloc.c
Bryan Wu's avatar
Bryan Wu committed
3 4 5 6
 * Based on:
 * Author:
 *
 * Created:
7
 * Description:  SRAM allocator for Blackfin L1 and L2 memory
Bryan Wu's avatar
Bryan Wu committed
8 9
 *
 * Modified:
10
 *               Copyright 2004-2008 Analog Devices Inc.
Bryan Wu's avatar
Bryan Wu committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see the file COPYING, or write
 * to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/rtc.h>
#include <asm/blackfin.h>
42
#include <asm/mem_map.h>
Bryan Wu's avatar
Bryan Wu committed
43 44 45
#include "blackfin_sram.h"

/* the data structure for L1 scratchpad and DATA SRAM */
46
struct sram_piece {
Bryan Wu's avatar
Bryan Wu committed
47 48
	void *paddr;
	int size;
49
	pid_t pid;
50
	struct sram_piece *next;
Bryan Wu's avatar
Bryan Wu committed
51 52
};

53
static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock);
54 55
static DEFINE_PER_CPU(struct sram_piece, free_l1_ssram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_ssram_head);
Bryan Wu's avatar
Bryan Wu committed
56 57

#if L1_DATA_A_LENGTH != 0
58 59
static DEFINE_PER_CPU(struct sram_piece, free_l1_data_A_sram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_data_A_sram_head);
Bryan Wu's avatar
Bryan Wu committed
60 61 62
#endif

#if L1_DATA_B_LENGTH != 0
63 64
static DEFINE_PER_CPU(struct sram_piece, free_l1_data_B_sram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_data_B_sram_head);
Bryan Wu's avatar
Bryan Wu committed
65 66
#endif

67 68 69 70
#if L1_DATA_A_LENGTH || L1_DATA_B_LENGTH
static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_data_sram_lock);
#endif

Bryan Wu's avatar
Bryan Wu committed
71
#if L1_CODE_LENGTH != 0
72
static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock);
73 74
static DEFINE_PER_CPU(struct sram_piece, free_l1_inst_sram_head);
static DEFINE_PER_CPU(struct sram_piece, used_l1_inst_sram_head);
Bryan Wu's avatar
Bryan Wu committed
75 76
#endif

77
#if L2_LENGTH != 0
78
static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
79 80 81
static struct sram_piece free_l2_sram_head, used_l2_sram_head;
#endif

82 83
static struct kmem_cache *sram_piece_cache;

Bryan Wu's avatar
Bryan Wu committed
84
/* L1 Scratchpad SRAM initialization function */
85
static void __init l1sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
86
{
87
	unsigned int cpu;
88 89 90 91 92 93 94 95
	unsigned long reserve;

#ifdef CONFIG_SMP
	reserve = 0;
#else
	reserve = sizeof(struct l1_scratch_task_info);
#endif

96 97 98 99 100 101 102 103
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
		per_cpu(free_l1_ssram_head, cpu).next =
			kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
		if (!per_cpu(free_l1_ssram_head, cpu).next) {
			printk(KERN_INFO "Fail to initialize Scratchpad data SRAM.\n");
			return;
		}

104 105
		per_cpu(free_l1_ssram_head, cpu).next->paddr = (void *)get_l1_scratch_start_cpu(cpu) + reserve;
		per_cpu(free_l1_ssram_head, cpu).next->size = L1_SCRATCH_LENGTH - reserve;
106 107 108 109 110 111 112 113 114
		per_cpu(free_l1_ssram_head, cpu).next->pid = 0;
		per_cpu(free_l1_ssram_head, cpu).next->next = NULL;

		per_cpu(used_l1_ssram_head, cpu).next = NULL;

		/* mutex initialize */
		spin_lock_init(&per_cpu(l1sram_lock, cpu));
		printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
			L1_SCRATCH_LENGTH >> 10);
115
	}
Bryan Wu's avatar
Bryan Wu committed
116 117
}

118
static void __init l1_data_sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
119
{
120
#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
121
	unsigned int cpu;
122
#endif
Bryan Wu's avatar
Bryan Wu committed
123
#if L1_DATA_A_LENGTH != 0
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
		per_cpu(free_l1_data_A_sram_head, cpu).next =
			kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
		if (!per_cpu(free_l1_data_A_sram_head, cpu).next) {
			printk(KERN_INFO "Fail to initialize L1 Data A SRAM.\n");
			return;
		}

		per_cpu(free_l1_data_A_sram_head, cpu).next->paddr =
			(void *)get_l1_data_a_start_cpu(cpu) + (_ebss_l1 - _sdata_l1);
		per_cpu(free_l1_data_A_sram_head, cpu).next->size =
			L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
		per_cpu(free_l1_data_A_sram_head, cpu).next->pid = 0;
		per_cpu(free_l1_data_A_sram_head, cpu).next->next = NULL;

		per_cpu(used_l1_data_A_sram_head, cpu).next = NULL;

		printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
			L1_DATA_A_LENGTH >> 10,
			per_cpu(free_l1_data_A_sram_head, cpu).next->size >> 10);
144
	}
Bryan Wu's avatar
Bryan Wu committed
145 146
#endif
#if L1_DATA_B_LENGTH != 0
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
		per_cpu(free_l1_data_B_sram_head, cpu).next =
			kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
		if (!per_cpu(free_l1_data_B_sram_head, cpu).next) {
			printk(KERN_INFO "Fail to initialize L1 Data B SRAM.\n");
			return;
		}

		per_cpu(free_l1_data_B_sram_head, cpu).next->paddr =
			(void *)get_l1_data_b_start_cpu(cpu) + (_ebss_b_l1 - _sdata_b_l1);
		per_cpu(free_l1_data_B_sram_head, cpu).next->size =
			L1_DATA_B_LENGTH - (_ebss_b_l1 - _sdata_b_l1);
		per_cpu(free_l1_data_B_sram_head, cpu).next->pid = 0;
		per_cpu(free_l1_data_B_sram_head, cpu).next->next = NULL;

		per_cpu(used_l1_data_B_sram_head, cpu).next = NULL;

		printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
			L1_DATA_B_LENGTH >> 10,
			per_cpu(free_l1_data_B_sram_head, cpu).next->size >> 10);
		/* mutex initialize */
168
	}
Bryan Wu's avatar
Bryan Wu committed
169 170
#endif

171 172 173 174
#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu)
		spin_lock_init(&per_cpu(l1_data_sram_lock, cpu));
#endif
Bryan Wu's avatar
Bryan Wu committed
175 176
}

177
static void __init l1_inst_sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
178 179
{
#if L1_CODE_LENGTH != 0
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	unsigned int cpu;
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
		per_cpu(free_l1_inst_sram_head, cpu).next =
			kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
		if (!per_cpu(free_l1_inst_sram_head, cpu).next) {
			printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
			return;
		}

		per_cpu(free_l1_inst_sram_head, cpu).next->paddr =
			(void *)get_l1_code_start_cpu(cpu) + (_etext_l1 - _stext_l1);
		per_cpu(free_l1_inst_sram_head, cpu).next->size =
			L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
		per_cpu(free_l1_inst_sram_head, cpu).next->pid = 0;
		per_cpu(free_l1_inst_sram_head, cpu).next->next = NULL;

		per_cpu(used_l1_inst_sram_head, cpu).next = NULL;

		printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
			L1_CODE_LENGTH >> 10,
			per_cpu(free_l1_inst_sram_head, cpu).next->size >> 10);

		/* mutex initialize */
		spin_lock_init(&per_cpu(l1_inst_sram_lock, cpu));
204
	}
Bryan Wu's avatar
Bryan Wu committed
205 206 207
#endif
}

208 209
static void __init l2_sram_init(void)
{
210
#if L2_LENGTH != 0
211 212 213
	free_l2_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l2_sram_head.next) {
214
		printk(KERN_INFO "Fail to initialize L2 SRAM.\n");
215 216 217
		return;
	}

218 219 220 221
	free_l2_sram_head.next->paddr =
		(void *)L2_START + (_ebss_l2 - _stext_l2);
	free_l2_sram_head.next->size =
		L2_LENGTH - (_ebss_l2 - _stext_l2);
222 223 224 225 226 227 228 229 230 231 232
	free_l2_sram_head.next->pid = 0;
	free_l2_sram_head.next->next = NULL;

	used_l2_sram_head.next = NULL;

	printk(KERN_INFO "Blackfin L2 SRAM: %d KB (%d KB free)\n",
		L2_LENGTH >> 10,
		free_l2_sram_head.next->size >> 10);

	/* mutex initialize */
	spin_lock_init(&l2_sram_lock);
233
#endif
234
}
235

236
static int __init bfin_sram_init(void)
237 238 239 240 241 242 243 244
{
	sram_piece_cache = kmem_cache_create("sram_piece_cache",
				sizeof(struct sram_piece),
				0, SLAB_PANIC, NULL);

	l1sram_init();
	l1_data_sram_init();
	l1_inst_sram_init();
245
	l2_sram_init();
246 247

	return 0;
248
}
249
pure_initcall(bfin_sram_init);
250

251 252
/* SRAM allocate function */
static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
253
		struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
254
{
255
	struct sram_piece *pslot, *plast, *pavail;
Bryan Wu's avatar
Bryan Wu committed
256

257
	if (size <= 0 || !pfree_head || !pused_head)
Bryan Wu's avatar
Bryan Wu committed
258 259 260 261 262
		return NULL;

	/* Align the size */
	size = (size + 3) & ~3;

263 264 265 266 267 268 269
	pslot = pfree_head->next;
	plast = pfree_head;

	/* search an available piece slot */
	while (pslot != NULL && size > pslot->size) {
		plast = pslot;
		pslot = pslot->next;
Bryan Wu's avatar
Bryan Wu committed
270
	}
271 272

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
273 274
		return NULL;

275 276 277 278 279 280 281 282 283 284 285 286 287
	if (pslot->size == size) {
		plast->next = pslot->next;
		pavail = pslot;
	} else {
		pavail = kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);

		if (!pavail)
			return NULL;

		pavail->paddr = pslot->paddr;
		pavail->size = size;
		pslot->paddr += size;
		pslot->size -= size;
Bryan Wu's avatar
Bryan Wu committed
288 289
	}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
	pavail->pid = current->pid;

	pslot = pused_head->next;
	plast = pused_head;

	/* insert new piece into used piece list !!! */
	while (pslot != NULL && pavail->paddr < pslot->paddr) {
		plast = pslot;
		pslot = pslot->next;
	}

	pavail->next = pslot;
	plast->next = pavail;

	return pavail->paddr;
Bryan Wu's avatar
Bryan Wu committed
305 306 307
}

/* Allocate the largest available block.  */
308
static void *_sram_alloc_max(struct sram_piece *pfree_head,
309
				struct sram_piece *pused_head,
Bryan Wu's avatar
Bryan Wu committed
310 311
				unsigned long *psize)
{
312 313 314 315 316 317
	struct sram_piece *pslot, *pmax;

	if (!pfree_head || !pused_head)
		return NULL;

	pmax = pslot = pfree_head->next;
Bryan Wu's avatar
Bryan Wu committed
318

319 320 321 322 323
	/* search an available piece slot */
	while (pslot != NULL) {
		if (pslot->size > pmax->size)
			pmax = pslot;
		pslot = pslot->next;
Bryan Wu's avatar
Bryan Wu committed
324
	}
325 326

	if (!pmax)
Bryan Wu's avatar
Bryan Wu committed
327 328
		return NULL;

329 330
	*psize = pmax->size;

331
	return _sram_alloc(*psize, pfree_head, pused_head);
Bryan Wu's avatar
Bryan Wu committed
332 333
}

334 335
/* SRAM free function */
static int _sram_free(const void *addr,
336 337
			struct sram_piece *pfree_head,
			struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
338
{
339 340 341 342
	struct sram_piece *pslot, *plast, *pavail;

	if (!pfree_head || !pused_head)
		return -1;
Bryan Wu's avatar
Bryan Wu committed
343 344

	/* search the relevant memory slot */
345 346 347 348 349 350 351
	pslot = pused_head->next;
	plast = pused_head;

	/* search an available piece slot */
	while (pslot != NULL && pslot->paddr != addr) {
		plast = pslot;
		pslot = pslot->next;
Bryan Wu's avatar
Bryan Wu committed
352
	}
353 354

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
355 356
		return -1;

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	plast->next = pslot->next;
	pavail = pslot;
	pavail->pid = 0;

	/* insert free pieces back to the free list */
	pslot = pfree_head->next;
	plast = pfree_head;

	while (pslot != NULL && addr > pslot->paddr) {
		plast = pslot;
		pslot = pslot->next;
	}

	if (plast != pfree_head && plast->paddr + plast->size == pavail->paddr) {
		plast->size += pavail->size;
		kmem_cache_free(sram_piece_cache, pavail);
	} else {
374
		pavail->next = plast->next;
375 376
		plast->next = pavail;
		plast = pavail;
Bryan Wu's avatar
Bryan Wu committed
377 378
	}

379 380 381 382
	if (pslot && plast->paddr + plast->size == pslot->paddr) {
		plast->size += pslot->size;
		plast->next = pslot->next;
		kmem_cache_free(sram_piece_cache, pslot);
Bryan Wu's avatar
Bryan Wu committed
383 384 385 386 387 388 389
	}

	return 0;
}

int sram_free(const void *addr)
{
390

Bryan Wu's avatar
Bryan Wu committed
391
#if L1_CODE_LENGTH != 0
392 393
	if (addr >= (void *)get_l1_code_start()
		 && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH))
Bryan Wu's avatar
Bryan Wu committed
394
		return l1_inst_sram_free(addr);
395
	else
Bryan Wu's avatar
Bryan Wu committed
396 397
#endif
#if L1_DATA_A_LENGTH != 0
398 399
	if (addr >= (void *)get_l1_data_a_start()
		 && addr < (void *)(get_l1_data_a_start() + L1_DATA_A_LENGTH))
Bryan Wu's avatar
Bryan Wu committed
400
		return l1_data_A_sram_free(addr);
401
	else
Bryan Wu's avatar
Bryan Wu committed
402 403
#endif
#if L1_DATA_B_LENGTH != 0
404 405
	if (addr >= (void *)get_l1_data_b_start()
		 && addr < (void *)(get_l1_data_b_start() + L1_DATA_B_LENGTH))
Bryan Wu's avatar
Bryan Wu committed
406
		return l1_data_B_sram_free(addr);
407
	else
408
#endif
409
#if L2_LENGTH != 0
410
	if (addr >= (void *)L2_START
411 412
		 && addr < (void *)(L2_START + L2_LENGTH))
		return l2_sram_free(addr);
Bryan Wu's avatar
Bryan Wu committed
413
	else
414
#endif
Bryan Wu's avatar
Bryan Wu committed
415 416 417 418 419 420
		return -1;
}
EXPORT_SYMBOL(sram_free);

void *l1_data_A_sram_alloc(size_t size)
{
421
#if L1_DATA_A_LENGTH != 0
422
	unsigned long flags;
423
	void *addr;
424
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
425

426
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
427
	/* add mutex operation */
428
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
429

430 431
	addr = _sram_alloc(size, &per_cpu(free_l1_data_A_sram_head, cpu),
			&per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
432 433

	/* add mutex operation */
434 435
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
436 437 438 439 440

	pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
		 (long unsigned int)addr, size);

	return addr;
441 442 443
#else
	return NULL;
#endif
Bryan Wu's avatar
Bryan Wu committed
444 445 446 447 448
}
EXPORT_SYMBOL(l1_data_A_sram_alloc);

int l1_data_A_sram_free(const void *addr)
{
449
#if L1_DATA_A_LENGTH != 0
450
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
451
	int ret;
452
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
453

454
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
455
	/* add mutex operation */
456
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
457

458 459
	ret = _sram_free(addr, &per_cpu(free_l1_data_A_sram_head, cpu),
			&per_cpu(used_l1_data_A_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
460 461

	/* add mutex operation */
462 463
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
464 465

	return ret;
466 467 468
#else
	return -1;
#endif
Bryan Wu's avatar
Bryan Wu committed
469 470 471 472 473 474
}
EXPORT_SYMBOL(l1_data_A_sram_free);

void *l1_data_B_sram_alloc(size_t size)
{
#if L1_DATA_B_LENGTH != 0
475
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
476
	void *addr;
477
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
478

479
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
480
	/* add mutex operation */
481
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
482

483 484
	addr = _sram_alloc(size, &per_cpu(free_l1_data_B_sram_head, cpu),
			&per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
485 486

	/* add mutex operation */
487 488
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
489 490 491 492 493 494 495 496 497 498 499 500 501 502

	pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
		 (long unsigned int)addr, size);

	return addr;
#else
	return NULL;
#endif
}
EXPORT_SYMBOL(l1_data_B_sram_alloc);

int l1_data_B_sram_free(const void *addr)
{
#if L1_DATA_B_LENGTH != 0
503
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
504
	int ret;
505
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
506

507
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
508
	/* add mutex operation */
509
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
510

511 512
	ret = _sram_free(addr, &per_cpu(free_l1_data_B_sram_head, cpu),
			&per_cpu(used_l1_data_B_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
513 514

	/* add mutex operation */
515 516
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

	return ret;
#else
	return -1;
#endif
}
EXPORT_SYMBOL(l1_data_B_sram_free);

void *l1_data_sram_alloc(size_t size)
{
	void *addr = l1_data_A_sram_alloc(size);

	if (!addr)
		addr = l1_data_B_sram_alloc(size);

	return addr;
}
EXPORT_SYMBOL(l1_data_sram_alloc);

void *l1_data_sram_zalloc(size_t size)
{
	void *addr = l1_data_sram_alloc(size);

	if (addr)
		memset(addr, 0x00, size);

	return addr;
}
EXPORT_SYMBOL(l1_data_sram_zalloc);

int l1_data_sram_free(const void *addr)
{
	int ret;
	ret = l1_data_A_sram_free(addr);
	if (ret == -1)
		ret = l1_data_B_sram_free(addr);
	return ret;
}
EXPORT_SYMBOL(l1_data_sram_free);

void *l1_inst_sram_alloc(size_t size)
{
559
#if L1_CODE_LENGTH != 0
560
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
561
	void *addr;
562
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
563

564
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
565
	/* add mutex operation */
566
	spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
567

568 569
	addr = _sram_alloc(size, &per_cpu(free_l1_inst_sram_head, cpu),
			&per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
570 571

	/* add mutex operation */
572 573
	spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
574 575 576 577 578 579 580 581 582 583 584 585 586 587

	pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
		 (long unsigned int)addr, size);

	return addr;
#else
	return NULL;
#endif
}
EXPORT_SYMBOL(l1_inst_sram_alloc);

int l1_inst_sram_free(const void *addr)
{
#if L1_CODE_LENGTH != 0
588
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
589
	int ret;
590
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
591

592
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
593
	/* add mutex operation */
594
	spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
595

596 597
	ret = _sram_free(addr, &per_cpu(free_l1_inst_sram_head, cpu),
			&per_cpu(used_l1_inst_sram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
598 599

	/* add mutex operation */
600 601
	spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
602 603 604 605 606 607 608 609 610 611 612

	return ret;
#else
	return -1;
#endif
}
EXPORT_SYMBOL(l1_inst_sram_free);

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc(size_t size)
{
613
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
614
	void *addr;
615
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
616

617
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
618
	/* add mutex operation */
619
	spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
620

621 622
	addr = _sram_alloc(size, &per_cpu(free_l1_ssram_head, cpu),
			&per_cpu(used_l1_ssram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
623 624

	/* add mutex operation */
625 626
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
627 628 629 630 631 632 633

	return addr;
}

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc_max(size_t *psize)
{
634
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
635
	void *addr;
636
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
637

638
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
639
	/* add mutex operation */
640
	spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
641

642 643
	addr = _sram_alloc_max(&per_cpu(free_l1_ssram_head, cpu),
			&per_cpu(used_l1_ssram_head, cpu), psize);
Bryan Wu's avatar
Bryan Wu committed
644 645

	/* add mutex operation */
646 647
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
648 649 650 651 652 653 654

	return addr;
}

/* L1 Scratchpad memory free function */
int l1sram_free(const void *addr)
{
655
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
656
	int ret;
657
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
658

659
	cpu = get_cpu();
Bryan Wu's avatar
Bryan Wu committed
660
	/* add mutex operation */
661
	spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
662

663 664
	ret = _sram_free(addr, &per_cpu(free_l1_ssram_head, cpu),
			&per_cpu(used_l1_ssram_head, cpu));
Bryan Wu's avatar
Bryan Wu committed
665 666

	/* add mutex operation */
667 668
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
	put_cpu();
Bryan Wu's avatar
Bryan Wu committed
669 670 671 672

	return ret;
}

673 674
void *l2_sram_alloc(size_t size)
{
675
#if L2_LENGTH != 0
676
	unsigned long flags;
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	void *addr;

	/* add mutex operation */
	spin_lock_irqsave(&l2_sram_lock, flags);

	addr = _sram_alloc(size, &free_l2_sram_head,
			&used_l2_sram_head);

	/* add mutex operation */
	spin_unlock_irqrestore(&l2_sram_lock, flags);

	pr_debug("Allocated address in l2_sram_alloc is 0x%lx+0x%lx\n",
		 (long unsigned int)addr, size);

	return addr;
#else
	return NULL;
#endif
}
EXPORT_SYMBOL(l2_sram_alloc);

void *l2_sram_zalloc(size_t size)
{
	void *addr = l2_sram_alloc(size);

	if (addr)
		memset(addr, 0x00, size);

	return addr;
}
EXPORT_SYMBOL(l2_sram_zalloc);

int l2_sram_free(const void *addr)
{
711
#if L2_LENGTH != 0
712
	unsigned long flags;
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
	int ret;

	/* add mutex operation */
	spin_lock_irqsave(&l2_sram_lock, flags);

	ret = _sram_free(addr, &free_l2_sram_head,
			&used_l2_sram_head);

	/* add mutex operation */
	spin_unlock_irqrestore(&l2_sram_lock, flags);

	return ret;
#else
	return -1;
#endif
}
EXPORT_SYMBOL(l2_sram_free);

Bryan Wu's avatar
Bryan Wu committed
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
int sram_free_with_lsl(const void *addr)
{
	struct sram_list_struct *lsl, **tmp;
	struct mm_struct *mm = current->mm;

	for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
		if ((*tmp)->addr == addr)
			goto found;
	return -1;
found:
	lsl = *tmp;
	sram_free(addr);
	*tmp = lsl->next;
	kfree(lsl);

	return 0;
}
EXPORT_SYMBOL(sram_free_with_lsl);

750 751 752 753
/* Allocate memory and keep in L1 SRAM List (lsl) so that the resources are
 * tracked.  These are designed for userspace so that when a process exits,
 * we can safely reap their resources.
 */
Bryan Wu's avatar
Bryan Wu committed
754 755 756 757 758 759
void *sram_alloc_with_lsl(size_t size, unsigned long flags)
{
	void *addr = NULL;
	struct sram_list_struct *lsl = NULL;
	struct mm_struct *mm = current->mm;

760
	lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
Bryan Wu's avatar
Bryan Wu committed
761 762 763 764 765 766 767 768 769 770 771 772
	if (!lsl)
		return NULL;

	if (flags & L1_INST_SRAM)
		addr = l1_inst_sram_alloc(size);

	if (addr == NULL && (flags & L1_DATA_A_SRAM))
		addr = l1_data_A_sram_alloc(size);

	if (addr == NULL && (flags & L1_DATA_B_SRAM))
		addr = l1_data_B_sram_alloc(size);

773 774 775
	if (addr == NULL && (flags & L2_SRAM))
		addr = l2_sram_alloc(size);

Bryan Wu's avatar
Bryan Wu committed
776 777 778 779 780 781 782 783 784 785 786
	if (addr == NULL) {
		kfree(lsl);
		return NULL;
	}
	lsl->addr = addr;
	lsl->length = size;
	lsl->next = mm->context.sram_list;
	mm->context.sram_list = lsl;
	return addr;
}
EXPORT_SYMBOL(sram_alloc_with_lsl);
787 788 789 790 791

#ifdef CONFIG_PROC_FS
/* Once we get a real allocator, we'll throw all of this away.
 * Until then, we need some sort of visibility into the L1 alloc.
 */
792 793 794
/* Need to keep line of output the same.  Currently, that is 44 bytes
 * (including newline).
 */
795
static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
796 797
		struct sram_piece *pfree_head,
		struct sram_piece *pused_head)
798
{
799 800 801 802
	struct sram_piece *pslot;

	if (!pfree_head || !pused_head)
		return -1;
803

804
	*len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
805 806 807 808 809

	/* search the relevant memory slot */
	pslot = pused_head->next;

	while (pslot != NULL) {
810
		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
811 812 813 814 815 816 817 818 819
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "ALLOCATED");

		pslot = pslot->next;
	}

	pslot = pfree_head->next;

	while (pslot != NULL) {
820
		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
821 822 823 824
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "FREE");

		pslot = pslot->next;
825
	}
826 827

	return 0;
828
}
829
static int sram_proc_read(char *buf, char **start, off_t offset, int count,
830 831 832
		int *eof, void *data)
{
	int len = 0;
833
	unsigned int cpu;
834

835 836 837 838
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
		if (_sram_proc_read(buf, &len, count, "Scratchpad",
			&per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
			goto not_done;
839
#if L1_DATA_A_LENGTH != 0
840 841 842 843
		if (_sram_proc_read(buf, &len, count, "L1 Data A",
			&per_cpu(free_l1_data_A_sram_head, cpu),
			&per_cpu(used_l1_data_A_sram_head, cpu)))
			goto not_done;
844 845
#endif
#if L1_DATA_B_LENGTH != 0
846 847 848 849
		if (_sram_proc_read(buf, &len, count, "L1 Data B",
			&per_cpu(free_l1_data_B_sram_head, cpu),
			&per_cpu(used_l1_data_B_sram_head, cpu)))
			goto not_done;
850 851
#endif
#if L1_CODE_LENGTH != 0
852 853 854 855
		if (_sram_proc_read(buf, &len, count, "L1 Instruction",
			&per_cpu(free_l1_inst_sram_head, cpu),
			&per_cpu(used_l1_inst_sram_head, cpu)))
			goto not_done;
856
#endif
857
	}
858
#if L2_LENGTH != 0
859 860
	if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
		&used_l2_sram_head))
861 862
		goto not_done;
#endif
863 864
	*eof = 1;
 not_done:
865 866 867
	return len;
}

868
static int __init sram_proc_init(void)
869 870 871 872 873 874 875
{
	struct proc_dir_entry *ptr;
	ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
	if (!ptr) {
		printk(KERN_WARNING "unable to create /proc/sram\n");
		return -1;
	}
876
	ptr->read_proc = sram_proc_read;
877 878
	return 0;
}
879
late_initcall(sram_proc_init);
880
#endif