sram-alloc.c 17.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 42 43
 *
 * 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>
#include "blackfin_sram.h"

44
static spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
45
static spinlock_t l2_sram_lock;
Bryan Wu's avatar
Bryan Wu committed
46 47

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

55
static struct sram_piece free_l1_ssram_head, used_l1_ssram_head;
Bryan Wu's avatar
Bryan Wu committed
56 57

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

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

#if L1_CODE_LENGTH != 0
66
static struct sram_piece free_l1_inst_sram_head, used_l1_inst_sram_head;
Bryan Wu's avatar
Bryan Wu committed
67 68
#endif

69
#if L2_LENGTH != 0
70 71 72
static struct sram_piece free_l2_sram_head, used_l2_sram_head;
#endif

73 74
static struct kmem_cache *sram_piece_cache;

Bryan Wu's avatar
Bryan Wu committed
75
/* L1 Scratchpad SRAM initialization function */
76
static void __init l1sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
77
{
78 79 80
	free_l1_ssram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l1_ssram_head.next) {
81
		printk(KERN_INFO "Failed to initialize Scratchpad data SRAM\n");
82 83
		return;
	}
Bryan Wu's avatar
Bryan Wu committed
84

85 86 87 88 89 90
	free_l1_ssram_head.next->paddr = (void *)L1_SCRATCH_START;
	free_l1_ssram_head.next->size = L1_SCRATCH_LENGTH;
	free_l1_ssram_head.next->pid = 0;
	free_l1_ssram_head.next->next = NULL;

	used_l1_ssram_head.next = NULL;
Bryan Wu's avatar
Bryan Wu committed
91 92 93

	/* mutex initialize */
	spin_lock_init(&l1sram_lock);
94 95 96

	printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
	       L1_SCRATCH_LENGTH >> 10);
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
102 103 104
	free_l1_data_A_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l1_data_A_sram_head.next) {
105
		printk(KERN_INFO "Failed to initialize L1 Data A SRAM\n");
106 107 108 109 110 111 112 113 114 115 116
		return;
	}

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

	used_l1_data_A_sram_head.next = NULL;
117

118
	printk(KERN_INFO "Blackfin L1 Data A SRAM: %d KB (%d KB free)\n",
119 120
		L1_DATA_A_LENGTH >> 10,
		free_l1_data_A_sram_head.next->size >> 10);
Bryan Wu's avatar
Bryan Wu committed
121 122
#endif
#if L1_DATA_B_LENGTH != 0
123 124 125
	free_l1_data_B_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l1_data_B_sram_head.next) {
126
		printk(KERN_INFO "Failed to initialize L1 Data B SRAM\n");
127 128 129 130 131 132 133 134 135 136 137
		return;
	}

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

	used_l1_data_B_sram_head.next = NULL;
138

139
	printk(KERN_INFO "Blackfin L1 Data B SRAM: %d KB (%d KB free)\n",
140 141
		L1_DATA_B_LENGTH >> 10,
		free_l1_data_B_sram_head.next->size >> 10);
Bryan Wu's avatar
Bryan Wu committed
142 143 144 145 146 147
#endif

	/* mutex initialize */
	spin_lock_init(&l1_data_sram_lock);
}

148
static void __init l1_inst_sram_init(void)
Bryan Wu's avatar
Bryan Wu committed
149 150
{
#if L1_CODE_LENGTH != 0
151 152 153
	free_l1_inst_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l1_inst_sram_head.next) {
154
		printk(KERN_INFO "Failed to initialize L1 Instruction SRAM\n");
155 156 157 158 159 160 161 162 163 164 165
		return;
	}

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

	used_l1_inst_sram_head.next = NULL;
166

167
	printk(KERN_INFO "Blackfin L1 Instruction SRAM: %d KB (%d KB free)\n",
168 169
		L1_CODE_LENGTH >> 10,
		free_l1_inst_sram_head.next->size >> 10);
Bryan Wu's avatar
Bryan Wu committed
170 171 172 173 174 175
#endif

	/* mutex initialize */
	spin_lock_init(&l1_inst_sram_lock);
}

176 177
static void __init l2_sram_init(void)
{
178
#if L2_LENGTH != 0
179 180 181
	free_l2_sram_head.next =
		kmem_cache_alloc(sram_piece_cache, GFP_KERNEL);
	if (!free_l2_sram_head.next) {
182
		printk(KERN_INFO "Failed to initialize L2 SRAM\n");
183 184 185
		return;
	}

186 187 188 189
	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);
190 191 192 193 194 195 196 197 198 199 200 201 202
	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);
#endif

	/* mutex initialize */
	spin_lock_init(&l2_sram_lock);
}
203 204 205 206 207 208 209 210 211
void __init bfin_sram_init(void)
{
	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();
212
	l2_sram_init();
213 214
}

215 216
/* SRAM allocate function */
static void *_sram_alloc(size_t size, struct sram_piece *pfree_head,
217
		struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
218
{
219
	struct sram_piece *pslot, *plast, *pavail;
Bryan Wu's avatar
Bryan Wu committed
220

221
	if (size <= 0 || !pfree_head || !pused_head)
Bryan Wu's avatar
Bryan Wu committed
222 223 224 225 226
		return NULL;

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

227 228 229 230 231 232 233
	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
234
	}
235 236

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
237 238
		return NULL;

239 240 241 242 243 244 245 246 247 248 249 250 251
	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
252 253
	}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	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
269 270 271
}

/* Allocate the largest available block.  */
272
static void *_sram_alloc_max(struct sram_piece *pfree_head,
273
				struct sram_piece *pused_head,
Bryan Wu's avatar
Bryan Wu committed
274 275
				unsigned long *psize)
{
276 277 278 279 280 281
	struct sram_piece *pslot, *pmax;

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

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

283 284 285 286 287
	/* 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
288
	}
289 290

	if (!pmax)
Bryan Wu's avatar
Bryan Wu committed
291 292
		return NULL;

293 294
	*psize = pmax->size;

295
	return _sram_alloc(*psize, pfree_head, pused_head);
Bryan Wu's avatar
Bryan Wu committed
296 297
}

298 299
/* SRAM free function */
static int _sram_free(const void *addr,
300 301
			struct sram_piece *pfree_head,
			struct sram_piece *pused_head)
Bryan Wu's avatar
Bryan Wu committed
302
{
303 304 305 306
	struct sram_piece *pslot, *plast, *pavail;

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

	/* search the relevant memory slot */
309 310 311 312 313 314 315
	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
316
	}
317 318

	if (!pslot)
Bryan Wu's avatar
Bryan Wu committed
319 320
		return -1;

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
	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 {
338
		pavail->next = plast->next;
339 340
		plast->next = pavail;
		plast = pavail;
Bryan Wu's avatar
Bryan Wu committed
341 342
	}

343 344 345 346
	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
347 348 349 350 351 352 353
	}

	return 0;
}

int sram_free(const void *addr)
{
354

Bryan Wu's avatar
Bryan Wu committed
355
#if L1_CODE_LENGTH != 0
356
	if (addr >= (void *)L1_CODE_START
Bryan Wu's avatar
Bryan Wu committed
357 358
		 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
		return l1_inst_sram_free(addr);
359
	else
Bryan Wu's avatar
Bryan Wu committed
360 361
#endif
#if L1_DATA_A_LENGTH != 0
362
	if (addr >= (void *)L1_DATA_A_START
Bryan Wu's avatar
Bryan Wu committed
363 364
		 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
		return l1_data_A_sram_free(addr);
365
	else
Bryan Wu's avatar
Bryan Wu committed
366 367
#endif
#if L1_DATA_B_LENGTH != 0
368
	if (addr >= (void *)L1_DATA_B_START
Bryan Wu's avatar
Bryan Wu committed
369 370
		 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
		return l1_data_B_sram_free(addr);
371
	else
372
#endif
373
#if L2_LENGTH != 0
374
	if (addr >= (void *)L2_START
375 376
		 && addr < (void *)(L2_START + L2_LENGTH))
		return l2_sram_free(addr);
Bryan Wu's avatar
Bryan Wu committed
377
	else
378
#endif
Bryan Wu's avatar
Bryan Wu committed
379 380 381 382 383 384
		return -1;
}
EXPORT_SYMBOL(sram_free);

void *l1_data_A_sram_alloc(size_t size)
{
385
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
386 387 388 389 390 391
	void *addr = NULL;

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

#if L1_DATA_A_LENGTH != 0
392
	addr = _sram_alloc(size, &free_l1_data_A_sram_head,
393
			&used_l1_data_A_sram_head);
Bryan Wu's avatar
Bryan Wu committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407
#endif

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

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

	return addr;
}
EXPORT_SYMBOL(l1_data_A_sram_alloc);

int l1_data_A_sram_free(const void *addr)
{
408
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
409 410 411 412 413 414
	int ret;

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

#if L1_DATA_A_LENGTH != 0
415
	ret = _sram_free(addr, &free_l1_data_A_sram_head,
416
			&used_l1_data_A_sram_head);
Bryan Wu's avatar
Bryan Wu committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430
#else
	ret = -1;
#endif

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

	return ret;
}
EXPORT_SYMBOL(l1_data_A_sram_free);

void *l1_data_B_sram_alloc(size_t size)
{
#if L1_DATA_B_LENGTH != 0
431
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
432 433 434 435 436
	void *addr;

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

437
	addr = _sram_alloc(size, &free_l1_data_B_sram_head,
438
			&used_l1_data_B_sram_head);
Bryan Wu's avatar
Bryan Wu committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455

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

	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
456
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
457 458 459 460 461
	int ret;

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

462
	ret = _sram_free(addr, &free_l1_data_B_sram_head,
463
			&used_l1_data_B_sram_head);
Bryan Wu's avatar
Bryan Wu committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508

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

	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)
{
509
#if L1_CODE_LENGTH != 0
510
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
511 512 513 514 515
	void *addr;

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

516
	addr = _sram_alloc(size, &free_l1_inst_sram_head,
517
			&used_l1_inst_sram_head);
Bryan Wu's avatar
Bryan Wu committed
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

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

	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
535
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
536 537 538 539 540
	int ret;

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

541
	ret = _sram_free(addr, &free_l1_inst_sram_head,
542
			&used_l1_inst_sram_head);
Bryan Wu's avatar
Bryan Wu committed
543 544 545 546 547 548 549 550 551 552 553 554 555 556

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

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

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc(size_t size)
{
557
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
558 559 560 561 562
	void *addr;

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

563
	addr = _sram_alloc(size, &free_l1_ssram_head,
564
			&used_l1_ssram_head);
Bryan Wu's avatar
Bryan Wu committed
565 566 567 568 569 570 571 572 573 574

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

	return addr;
}

/* L1 Scratchpad memory allocate function */
void *l1sram_alloc_max(size_t *psize)
{
575
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
576 577 578 579 580
	void *addr;

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

581
	addr = _sram_alloc_max(&free_l1_ssram_head,
582
			&used_l1_ssram_head, psize);
Bryan Wu's avatar
Bryan Wu committed
583 584 585 586 587 588 589 590 591 592

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

	return addr;
}

/* L1 Scratchpad memory free function */
int l1sram_free(const void *addr)
{
593
	unsigned long flags;
Bryan Wu's avatar
Bryan Wu committed
594 595 596 597 598
	int ret;

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

599
	ret = _sram_free(addr, &free_l1_ssram_head,
600
			&used_l1_ssram_head);
Bryan Wu's avatar
Bryan Wu committed
601 602 603 604 605 606 607

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

	return ret;
}

608 609
void *l2_sram_alloc(size_t size)
{
610
#if L2_LENGTH != 0
611
	unsigned long flags;
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
	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)
{
646
#if L2_LENGTH != 0
647
	unsigned long flags;
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
	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
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
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);

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;

691
	lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
Bryan Wu's avatar
Bryan Wu committed
692 693 694 695 696 697 698 699 700 701 702 703
	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);

704 705 706
	if (addr == NULL && (flags & L2_SRAM))
		addr = l2_sram_alloc(size);

Bryan Wu's avatar
Bryan Wu committed
707 708 709 710 711 712 713 714 715 716 717
	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);
718 719 720 721 722

#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.
 */
723 724 725
/* Need to keep line of output the same.  Currently, that is 44 bytes
 * (including newline).
 */
726
static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
727 728
		struct sram_piece *pfree_head,
		struct sram_piece *pused_head)
729
{
730 731 732 733
	struct sram_piece *pslot;

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

735
	*len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
736 737 738 739 740

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

	while (pslot != NULL) {
741
		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
742 743 744 745 746 747 748 749 750
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "ALLOCATED");

		pslot = pslot->next;
	}

	pslot = pfree_head->next;

	while (pslot != NULL) {
751
		*len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
752 753 754 755
			pslot->paddr, pslot->paddr + pslot->size,
			pslot->size, pslot->pid, "FREE");

		pslot = pslot->next;
756
	}
757 758

	return 0;
759
}
760
static int sram_proc_read(char *buf, char **start, off_t offset, int count,
761 762 763 764
		int *eof, void *data)
{
	int len = 0;

765
	if (_sram_proc_read(buf, &len, count, "Scratchpad",
766
			&free_l1_ssram_head, &used_l1_ssram_head))
767
		goto not_done;
768
#if L1_DATA_A_LENGTH != 0
769
	if (_sram_proc_read(buf, &len, count, "L1 Data A",
770 771
			&free_l1_data_A_sram_head,
			&used_l1_data_A_sram_head))
772
		goto not_done;
773 774
#endif
#if L1_DATA_B_LENGTH != 0
775
	if (_sram_proc_read(buf, &len, count, "L1 Data B",
776 777
			&free_l1_data_B_sram_head,
			&used_l1_data_B_sram_head))
778
		goto not_done;
779 780
#endif
#if L1_CODE_LENGTH != 0
781
	if (_sram_proc_read(buf, &len, count, "L1 Instruction",
782
			&free_l1_inst_sram_head, &used_l1_inst_sram_head))
783
		goto not_done;
784
#endif
785
#if L2_LENGTH != 0
786 787 788 789
	if (_sram_proc_read(buf, &len, count, "L2",
			&free_l2_sram_head, &used_l2_sram_head))
		goto not_done;
#endif
790

791 792
	*eof = 1;
 not_done:
793 794 795
	return len;
}

796
static int __init sram_proc_init(void)
797 798 799 800 801 802 803 804
{
	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;
	}
	ptr->owner = THIS_MODULE;
805
	ptr->read_proc = sram_proc_read;
806 807
	return 0;
}
808
late_initcall(sram_proc_init);
809
#endif