sram-alloc.c 20 KB
Newer Older
Bryan Wu's avatar
Bryan Wu committed
1
/*
2
 * SRAM allocator for Blackfin on-chip memory
Bryan Wu's avatar
Bryan Wu committed
3
 *
4
 * Copyright 2004-2009 Analog Devices Inc.
Bryan Wu's avatar
Bryan Wu committed
5
 *
6
 * Licensed under the GPL-2 or later.
Bryan Wu's avatar
Bryan Wu committed
7 8 9 10 11 12 13 14 15 16 17
 */

#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>
18
#include <linux/seq_file.h>
Bryan Wu's avatar
Bryan Wu committed
19 20
#include <linux/spinlock.h>
#include <linux/rtc.h>
21
#include <linux/slab.h>
Bryan Wu's avatar
Bryan Wu committed
22
#include <asm/blackfin.h>
23
#include <asm/mem_map.h>
Bryan Wu's avatar
Bryan Wu committed
24 25 26
#include "blackfin_sram.h"

/* the data structure for L1 scratchpad and DATA SRAM */
27
struct sram_piece {
Bryan Wu's avatar
Bryan Wu committed
28 29
	void *paddr;
	int size;
30
	pid_t pid;
31
	struct sram_piece *next;
Bryan Wu's avatar
Bryan Wu committed
32 33
};

34
static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock);
35 36
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
37 38

#if L1_DATA_A_LENGTH != 0
39 40
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
41 42 43
#endif

#if L1_DATA_B_LENGTH != 0
44 45
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
46 47
#endif

48 49 50 51
#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
52
#if L1_CODE_LENGTH != 0
53
static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock);
54 55
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
56 57
#endif

58
#if L2_LENGTH != 0
59
static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
60 61 62
static struct sram_piece free_l2_sram_head, used_l2_sram_head;
#endif

63 64
static struct kmem_cache *sram_piece_cache;

Bryan Wu's avatar
Bryan Wu committed
65
/* L1 Scratchpad SRAM initialization function */
66
static void __init l1sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
67
{
68
	unsigned int cpu;
69 70 71 72 73 74 75 76
	unsigned long reserve;

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

77 78 79 80 81 82 83 84
	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;
		}

85 86
		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;
87 88 89 90 91 92 93 94 95
		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);
96
	}
Bryan Wu's avatar
Bryan Wu committed
97 98
}

99
static void __init l1_data_sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
100
{
101
#if L1_DATA_A_LENGTH != 0 || L1_DATA_B_LENGTH != 0
102
	unsigned int cpu;
103
#endif
Bryan Wu's avatar
Bryan Wu committed
104
#if L1_DATA_A_LENGTH != 0
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	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);
125
	}
Bryan Wu's avatar
Bryan Wu committed
126 127
#endif
#if L1_DATA_B_LENGTH != 0
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	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 */
149
	}
Bryan Wu's avatar
Bryan Wu committed
150 151
#endif

152 153 154 155
#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
156 157
}

158
static void __init l1_inst_sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
159 160
{
#if L1_CODE_LENGTH != 0
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
	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));
185
	}
Bryan Wu's avatar
Bryan Wu committed
186 187 188
#endif
}

189 190
static void __init l2_sram_init(void)
{
191
#if L2_LENGTH != 0
192 193 194
	free_l2_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l2_sram_head.next) {
195
		printk(KERN_INFO "Fail to initialize L2 SRAM.\n");
196 197 198
		return;
	}

199 200 201 202
	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);
203 204 205 206 207 208 209 210 211 212 213
	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);
214
#endif
215
}
216

217
static int __init bfin_sram_init(void)
218 219 220 221 222 223 224 225
{
	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();
226
	l2_sram_init();
227 228

	return 0;
229
}
230
pure_initcall(bfin_sram_init);
231

232 233
/* SRAM allocate function */
static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
234
		struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
235
{
236
	struct sram_piece *pslot, *plast, *pavail;
Bryan Wu's avatar
Bryan Wu committed
237

238
	if (size <= 0 || !pfree_head || !pused_head)
Bryan Wu's avatar
Bryan Wu committed
239 240 241 242 243
		return NULL;

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

244 245 246 247 248 249 250
	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
251
	}
252 253

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
254 255
		return NULL;

256 257 258 259
	if (pslot->size == size) {
		plast->next = pslot->next;
		pavail = pslot;
	} else {
260 261
		/* use atomic so our L1 allocator can be used atomically */
		pavail = kmem_cache_alloc(sram_piece_cache, GFP_ATOMIC);
262 263 264 265 266 267 268 269

		if (!pavail)
			return NULL;

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

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	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
287 288 289
}

/* Allocate the largest available block.  */
290
static void *_sram_alloc_max(struct sram_piece *pfree_head,
291
				struct sram_piece *pused_head,
Bryan Wu's avatar
Bryan Wu committed
292 293
				unsigned long *psize)
{
294 295 296 297 298 299
	struct sram_piece *pslot, *pmax;

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

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

301 302 303 304 305
	/* 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
306
	}
307 308

	if (!pmax)
Bryan Wu's avatar
Bryan Wu committed
309 310
		return NULL;

311 312
	*psize = pmax->size;

313
	return _sram_alloc(*psize, pfree_head, pused_head);
Bryan Wu's avatar
Bryan Wu committed
314 315
}

316 317
/* SRAM free function */
static int _sram_free(const void *addr,
318 319
			struct sram_piece *pfree_head,
			struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
320
{
321 322 323 324
	struct sram_piece *pslot, *plast, *pavail;

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

	/* search the relevant memory slot */
327 328 329 330 331 332 333
	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
334
	}
335 336

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
337 338
		return -1;

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	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 {
356
		pavail->next = plast->next;
357 358
		plast->next = pavail;
		plast = pavail;
Bryan Wu's avatar
Bryan Wu committed
359 360
	}

361 362 363 364
	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
365 366 367 368 369 370 371
	}

	return 0;
}

int sram_free(const void *addr)
{
372

Bryan Wu's avatar
Bryan Wu committed
373
#if L1_CODE_LENGTH != 0
374 375
	if (addr >= (void *)get_l1_code_start()
		 && addr < (void *)(get_l1_code_start() + L1_CODE_LENGTH))
Bryan Wu's avatar
Bryan Wu committed
376
		return l1_inst_sram_free(addr);
377
	else
Bryan Wu's avatar
Bryan Wu committed
378 379
#endif
#if L1_DATA_A_LENGTH != 0
380 381
	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
382
		return l1_data_A_sram_free(addr);
383
	else
Bryan Wu's avatar
Bryan Wu committed
384 385
#endif
#if L1_DATA_B_LENGTH != 0
386 387
	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
388
		return l1_data_B_sram_free(addr);
389
	else
390
#endif
391
#if L2_LENGTH != 0
392
	if (addr >= (void *)L2_START
393 394
		 && addr < (void *)(L2_START + L2_LENGTH))
		return l2_sram_free(addr);
Bryan Wu's avatar
Bryan Wu committed
395
	else
396
#endif
Bryan Wu's avatar
Bryan Wu committed
397 398 399 400 401 402
		return -1;
}
EXPORT_SYMBOL(sram_free);

void *l1_data_A_sram_alloc(size_t size)
{
403
#if L1_DATA_A_LENGTH != 0
404
	unsigned long flags;
405
	void *addr;
406
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
407

408
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
409
	/* add mutex operation */
410
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
411

412 413
	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
414 415

	/* add mutex operation */
416
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
417 418 419 420 421

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

	return addr;
422 423 424
#else
	return NULL;
#endif
Bryan Wu's avatar
Bryan Wu committed
425 426 427 428 429
}
EXPORT_SYMBOL(l1_data_A_sram_alloc);

int l1_data_A_sram_free(const void *addr)
{
430
#if L1_DATA_A_LENGTH != 0
431
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
432
	int ret;
433
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
434

435
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
436
	/* add mutex operation */
437
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
438

439 440
	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
441 442

	/* add mutex operation */
443
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
444 445

	return ret;
446 447 448
#else
	return -1;
#endif
Bryan Wu's avatar
Bryan Wu committed
449 450 451 452 453 454
}
EXPORT_SYMBOL(l1_data_A_sram_free);

void *l1_data_B_sram_alloc(size_t size)
{
#if L1_DATA_B_LENGTH != 0
455
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
456
	void *addr;
457
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
458

459
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
460
	/* add mutex operation */
461
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
462

463 464
	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
465 466

	/* add mutex operation */
467
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481

	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
482
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
483
	int ret;
484
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
485

486
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
487
	/* add mutex operation */
488
	spin_lock_irqsave(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
489

490 491
	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
492 493

	/* add mutex operation */
494
	spin_unlock_irqrestore(&per_cpu(l1_data_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536

	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)
{
537
#if L1_CODE_LENGTH != 0
538
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
539
	void *addr;
540
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
541

542
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
543
	/* add mutex operation */
544
	spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
545

546 547
	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
548 549

	/* add mutex operation */
550
	spin_unlock_irqrestore(&per_cpu(l1_inst_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
551 552 553 554 555 556 557 558 559 560 561 562 563 564

	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
565
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
566
	int ret;
567
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
568

569
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
570
	/* add mutex operation */
571
	spin_lock_irqsave(&per_cpu(l1_inst_sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
572

573 574
	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
575 576

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

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

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc(size_t size)
{
589
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
590
	void *addr;
591
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
592

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

597 598
	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
599 600

	/* add mutex operation */
601
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
602 603 604 605 606 607 608

	return addr;
}

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc_max(size_t *psize)
{
609
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
610
	void *addr;
611
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
612

613
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
614
	/* add mutex operation */
615
	spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
616

617 618
	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
619 620

	/* add mutex operation */
621
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
622 623 624 625 626 627 628

	return addr;
}

/* L1 Scratchpad memory free function */
int l1sram_free(const void *addr)
{
629
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
630
	int ret;
631
	unsigned int cpu;
Bryan Wu's avatar
Bryan Wu committed
632

633
	cpu = smp_processor_id();
Bryan Wu's avatar
Bryan Wu committed
634
	/* add mutex operation */
635
	spin_lock_irqsave(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
636

637 638
	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
639 640

	/* add mutex operation */
641
	spin_unlock_irqrestore(&per_cpu(l1sram_lock, cpu), flags);
Bryan Wu's avatar
Bryan Wu committed
642 643 644 645

	return ret;
}

646 647
void *l2_sram_alloc(size_t size)
{
648
#if L2_LENGTH != 0
649
	unsigned long flags;
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
	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)
{
684
#if L2_LENGTH != 0
685
	unsigned long flags;
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
	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
704 705 706 707
int sram_free_with_lsl(const void *addr)
{
	struct sram_list_struct *lsl, **tmp;
	struct mm_struct *mm = current->mm;
708
	int ret = -1;
Bryan Wu's avatar
Bryan Wu committed
709 710

	for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
711 712 713 714 715 716 717
		if ((*tmp)->addr == addr) {
			lsl = *tmp;
			ret = sram_free(addr);
			*tmp = lsl->next;
			kfree(lsl);
			break;
		}
Bryan Wu's avatar
Bryan Wu committed
718

719
	return ret;
Bryan Wu's avatar
Bryan Wu committed
720 721 722
}
EXPORT_SYMBOL(sram_free_with_lsl);

723 724 725 726
/* 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
727 728 729 730 731 732
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;

733
	lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
Bryan Wu's avatar
Bryan Wu committed
734 735 736 737 738 739 740 741 742 743 744 745
	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);

746 747 748
	if (addr == NULL && (flags & L2_SRAM))
		addr = l2_sram_alloc(size);

Bryan Wu's avatar
Bryan Wu committed
749 750 751 752 753 754 755 756 757 758 759
	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);
760 761 762 763 764

#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.
 */
765 766 767
/* Need to keep line of output the same.  Currently, that is 44 bytes
 * (including newline).
 */
768
static int _sram_proc_show(struct seq_file *m, const char *desc,
769 770
		struct sram_piece *pfree_head,
		struct sram_piece *pused_head)
771
{
772 773 774 775
	struct sram_piece *pslot;

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

777
	seq_printf(m, "--- SRAM %-14s Size   PID State     \n", desc);
778 779 780 781 782

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

	while (pslot != NULL) {
783
		seq_printf(m, "%p-%p %10i %5i %-10s\n",
784 785 786 787 788 789 790 791 792
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "ALLOCATED");

		pslot = pslot->next;
	}

	pslot = pfree_head->next;

	while (pslot != NULL) {
793
		seq_printf(m, "%p-%p %10i %5i %-10s\n",
794 795 796 797
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "FREE");

		pslot = pslot->next;
798
	}
799 800

	return 0;
801
}
802
static int sram_proc_show(struct seq_file *m, void *v)
803
{
804
	unsigned int cpu;
805

806
	for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
807
		if (_sram_proc_show(m, "Scratchpad",
808 809
			&per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
			goto not_done;
810
#if L1_DATA_A_LENGTH != 0
811
		if (_sram_proc_show(m, "L1 Data A",
812 813 814
			&per_cpu(free_l1_data_A_sram_head, cpu),
			&per_cpu(used_l1_data_A_sram_head, cpu)))
			goto not_done;
815 816
#endif
#if L1_DATA_B_LENGTH != 0
817
		if (_sram_proc_show(m, "L1 Data B",
818 819 820
			&per_cpu(free_l1_data_B_sram_head, cpu),
			&per_cpu(used_l1_data_B_sram_head, cpu)))
			goto not_done;
821 822
#endif
#if L1_CODE_LENGTH != 0
823
		if (_sram_proc_show(m, "L1 Instruction",
824 825 826
			&per_cpu(free_l1_inst_sram_head, cpu),
			&per_cpu(used_l1_inst_sram_head, cpu)))
			goto not_done;
827
#endif
828
	}
829
#if L2_LENGTH != 0
830
	if (_sram_proc_show(m, "L2", &free_l2_sram_head, &used_l2_sram_head))
831 832
		goto not_done;
#endif
833
 not_done:
834 835 836 837 838 839
	return 0;
}

static int sram_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, sram_proc_show, NULL);
840 841
}

842 843 844 845 846 847 848
static const struct file_operations sram_proc_ops = {
	.open		= sram_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

849
static int __init sram_proc_init(void)
850 851
{
	struct proc_dir_entry *ptr;
852 853

	ptr = proc_create("sram", S_IRUGO, NULL, &sram_proc_ops);
854 855 856 857 858 859
	if (!ptr) {
		printk(KERN_WARNING "unable to create /proc/sram\n");
		return -1;
	}
	return 0;
}
860
late_initcall(sram_proc_init);
861
#endif