11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * arch/sh/kernel/cpu/sh4/sq.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General management API for SH-4 integrated Store Queues 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * Copyright (C) 2001 - 2006 Paul Mundt 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 M. R. Brown 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for more details. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 14d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#include <linux/cpu.h> 15d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#include <linux/bitmap.h> 168a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers#include <linux/device.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 21e4c2cfee5d5cf3e4c16b423be23551aeddf2717bPaul Mundt#include <linux/mm.h> 229f650cf2b811cfb605f10483eeb1dc86f43cdbcbPaul Mundt#include <linux/io.h> 23268bb0ce3e87872cb9290c322b0d35bce230d88fLinus Torvalds#include <linux/prefetch.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h> 25e4c2cfee5d5cf3e4c16b423be23551aeddf2717bPaul Mundt#include <asm/cacheflush.h> 26f15cbe6f1a4b4d9df59142fc8e4abb973302cf44Paul Mundt#include <cpu/sq.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstruct sq_mapping; 29d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 30d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstruct sq_mapping { 31d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt const char *name; 32d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 33d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned long sq_addr; 34d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned long addr; 35d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned int size; 36d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 37d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_mapping *next; 38d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt}; 39d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 40d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic struct sq_mapping *sq_mapping_list; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(sq_mapping_lock); 42e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic struct kmem_cache *sq_cache; 43d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic unsigned long *sq_bitmap; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#define store_queue_barrier() \ 46d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtdo { \ 479d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt (void)__raw_readl(P4SEG_STORE_QUE); \ 489d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt __raw_writel(0, P4SEG_STORE_QUE + 0); \ 499d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt __raw_writel(0, P4SEG_STORE_QUE + 8); \ 50d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt} while (0); 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sq_flush_range - Flush (prefetch) a specific SQ range 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @start: the store queue address to start flushing from 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @len: the length to flush 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Flushes the store queue cache from @start to @start + @len in a 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linear fashion. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sq_flush_range(unsigned long start, unsigned int len) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 62b05d1865b46ea72c66ba082598ba370582bb590ePaul Mundt unsigned long *sq = (unsigned long *)start; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Flush the queues */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (len >>= 5; len--; sq += 8) 66b05d1865b46ea72c66ba082598ba370582bb590ePaul Mundt prefetchw(sq); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for completion */ 69d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt store_queue_barrier(); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 719f650cf2b811cfb605f10483eeb1dc86f43cdbcbPaul MundtEXPORT_SYMBOL(sq_flush_range); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic inline void sq_mapping_list_add(struct sq_mapping *map) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 75d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_mapping **p, *tmp; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt spin_lock_irq(&sq_mapping_lock); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt p = &sq_mapping_list; 80d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt while ((tmp = *p) != NULL) 81d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt p = &tmp->next; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->next = tmp; 84d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt *p = map; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt spin_unlock_irq(&sq_mapping_lock); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic inline void sq_mapping_list_del(struct sq_mapping *map) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 91d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_mapping **p, *tmp; 92d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 93d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt spin_lock_irq(&sq_mapping_lock); 94d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 95d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next) 96d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (tmp == map) { 97d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt *p = tmp->next; 98d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt break; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt spin_unlock_irq(&sq_mapping_lock); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1047bdda6209f224aa784a036df54b22cb338d2e859Paul Mundtstatic int __sq_remap(struct sq_mapping *map, pgprot_t prot) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 106d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#if defined(CONFIG_MMU) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vm_struct *vma; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!vma) 111d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -ENOMEM; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vma->phys_addr = map->addr; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11537bda1da4570c2e9c6dd34e77d2120218e384950Paul Mundt if (ioremap_page_range((unsigned long)vma->addr, 11637bda1da4570c2e9c6dd34e77d2120218e384950Paul Mundt (unsigned long)vma->addr + map->size, 1177bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt vma->phys_addr, prot)) { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vunmap(vma->addr); 119d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EAGAIN; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 121d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#else 122d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt /* 123d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * Without an MMU (or with it turned off), this is much more 124d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * straightforward, as we can just load up each queue's QACR with 125d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * the physical address appropriately masked. 126d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt */ 1279d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt __raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0); 1289d56dd3b083a3bec56e9da35ce07baca81030b03Paul Mundt __raw_writel(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1); 129d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#endif 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return 0; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sq_remap - Map a physical address through the Store Queues 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @phys: Physical address of mapping. 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @size: Length of mapping. 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @name: User invoking mapping. 1397bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt * @prot: Protection bits. 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remaps the physical address @phys through the next available store queue 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address of @size length. @name is logged at boot time as well as through 143d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * the sysfs interface. 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 145d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtunsigned long sq_remap(unsigned long phys, unsigned int size, 1467bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt const char *name, pgprot_t prot) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sq_mapping *map; 149d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned long end; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int psz; 151d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt int ret, page; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't allow wraparound or zero size */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = phys + size - 1; 155d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!size || end < phys)) 156d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EINVAL; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't allow anyone to remap normal memory.. */ 158d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(phys < virt_to_phys(high_memory))) 159d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EINVAL; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys &= PAGE_MASK; 162d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt size = PAGE_ALIGN(end + 1) - phys; 163d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 164d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map = kmem_cache_alloc(sq_cache, GFP_KERNEL); 165d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!map)) 166d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -ENOMEM; 167d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 168d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->addr = phys; 169d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->size = size; 170d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->name = name; 171d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 1729f650cf2b811cfb605f10483eeb1dc86f43cdbcbPaul Mundt page = bitmap_find_free_region(sq_bitmap, 0x04000000 >> PAGE_SHIFT, 173d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt get_order(map->size)); 174d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(page < 0)) { 175d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt ret = -ENOSPC; 176d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt goto out; 177d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt } 178d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 179d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT); 180d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 1817bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt ret = __sq_remap(map, prot); 182d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(ret != 0)) 183d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt goto out; 184d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 185d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 186d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n", 187d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt likely(map->name) ? map->name : "???", 188d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt psz, psz == 1 ? " " : "s", 189d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt map->sq_addr, map->addr); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_mapping_list_add(map); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 193d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return map->sq_addr; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 195d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtout: 196d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kmem_cache_free(sq_cache, map); 197d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return ret; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1999f650cf2b811cfb605f10483eeb1dc86f43cdbcbPaul MundtEXPORT_SYMBOL(sq_remap); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sq_unmap - Unmap a Store Queue allocation 2036a9545bd95e88d61df942b9087cb59b8c7a6dc56Paul Mundt * @vaddr: Pre-allocated Store Queue mapping. 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unmaps the store queue allocation @map that was previously created by 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sq_remap(). Also frees up the pte that was previously inserted into 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the kernel page table and discards the UTLB translation. 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 209d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtvoid sq_unmap(unsigned long vaddr) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 211d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_mapping **p, *map; 212d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt int page; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 214d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt for (p = &sq_mapping_list; (map = *p); p = &map->next) 215d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (map->sq_addr == vaddr) 216d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt break; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 218d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!map)) { 219d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt printk("%s: bad store queue address 0x%08lx\n", 220866e6b9e5019e210d96ced31fbae531ed756e486Harvey Harrison __func__, vaddr); 221d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return; 222d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 224d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT; 225d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt bitmap_release_region(sq_bitmap, page, get_order(map->size)); 226d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 227d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#ifdef CONFIG_MMU 228b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt { 229b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt /* 230b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt * Tear down the VMA in the MMU case. 231b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt */ 232b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt struct vm_struct *vma; 233b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt 234b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK)); 235b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt if (!vma) { 236b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt printk(KERN_ERR "%s: bad address 0x%08lx\n", 237866e6b9e5019e210d96ced31fbae531ed756e486Harvey Harrison __func__, map->sq_addr); 238b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt return; 239b067c50a7f58838d8a53670ea3c07e18d7391900Paul Mundt } 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 241d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt#endif 242d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 243d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_mapping_list_del(map); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kmem_cache_free(sq_cache, map); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2479f650cf2b811cfb605f10483eeb1dc86f43cdbcbPaul MundtEXPORT_SYMBOL(sq_unmap); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 249d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt/* 250d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * Needlessly complex sysfs interface. Unfortunately it doesn't seem like 251d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * there is any other easy way to add things on a per-cpu basis without 252d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * putting the directory entries somewhere stupid and having to create 253d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * links in sysfs by hand back in to the per-cpu directories. 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 255d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * Some day we may want to have an additional abstraction per store 256d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * queue, but considering the kobject hell we already have to deal with, 257d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt * it's simply not worth the trouble. 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 259d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic struct kobject *sq_kobject[NR_CPUS]; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstruct sq_sysfs_attr { 262d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct attribute attr; 263d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt ssize_t (*show)(char *buf); 264d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt ssize_t (*store)(const char *buf, size_t count); 265d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt}; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26725478445c4a39318acbe08ba8df7945766cbb5b5Alexey Dobriyan#define to_sq_sysfs_attr(a) container_of(a, struct sq_sysfs_attr, attr) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr, 270d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt char *buf) 271d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt{ 272d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 274d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (likely(sattr->show)) 275d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return sattr->show(buf); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 277d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EIO; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 280d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr, 281d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt const char *buf, size_t count) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 283d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 285d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (likely(sattr->store)) 286d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return sattr->store(buf, count); 287d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 288d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EIO; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 291d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic ssize_t mapping_show(char *buf) 292d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt{ 293d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct sq_mapping **list, *entry; 294d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt char *p = buf; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt for (list = &sq_mapping_list; (entry = *list); list = &entry->next) 297d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", 298d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt entry->sq_addr, entry->sq_addr + entry->size, 299d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt entry->addr, entry->name); 300d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 301d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return p - buf; 302d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt} 303d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 304d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic ssize_t mapping_store(const char *buf, size_t count) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 306d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned long base = 0, len = 0; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 308d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sscanf(buf, "%lx %lx", &base, &len); 309d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (!base) 310d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -EIO; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 312d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (likely(len)) { 3137bdda6209f224aa784a036df54b22cb338d2e859Paul Mundt int ret = sq_remap(base, len, "Userspace", PAGE_SHARED); 314d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (ret < 0) 315d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return ret; 316d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt } else 317d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_unmap(base); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 319d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return count; 320d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 322d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic struct sq_sysfs_attr mapping_attr = 323d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt __ATTR(mapping, 0644, mapping_show, mapping_store); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 325d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic struct attribute *sq_sysfs_attrs[] = { 326d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt &mapping_attr.attr, 327d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt NULL, 328d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt}; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33052cf25d0ab7f78eeecc59ac652ed5090f69b619eEmese Revfystatic const struct sysfs_ops sq_sysfs_ops = { 331d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt .show = sq_sysfs_show, 332d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt .store = sq_sysfs_store, 333d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt}; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 335d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtstatic struct kobj_type ktype_percpu_entry = { 336d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt .sysfs_ops = &sq_sysfs_ops, 337d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt .default_attrs = sq_sysfs_attrs, 338d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt}; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34033dc5c1000c193084a70ffd8f3bd9c67d19f9159Paul Mundtstatic int sq_dev_add(struct device *dev, struct subsys_interface *sif) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3428a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers unsigned int cpu = dev->id; 343d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct kobject *kobj; 344d48b335256cd75fcb1a4abb3ce8136d8d9c931ccGreg Kroah-Hartman int error; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 346d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL); 347d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!sq_kobject[cpu])) 348d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return -ENOMEM; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 350d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kobj = sq_kobject[cpu]; 3518a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers error = kobject_init_and_add(kobj, &ktype_percpu_entry, &dev->kobj, 352d48b335256cd75fcb1a4abb3ce8136d8d9c931ccGreg Kroah-Hartman "%s", "sq"); 353d48b335256cd75fcb1a4abb3ce8136d8d9c931ccGreg Kroah-Hartman if (!error) 354d48b335256cd75fcb1a4abb3ce8136d8d9c931ccGreg Kroah-Hartman kobject_uevent(kobj, KOBJ_ADD); 355d48b335256cd75fcb1a4abb3ce8136d8d9c931ccGreg Kroah-Hartman return error; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35833dc5c1000c193084a70ffd8f3bd9c67d19f9159Paul Mundtstatic int sq_dev_remove(struct device *dev, struct subsys_interface *sif) 359d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt{ 3608a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers unsigned int cpu = dev->id; 361d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt struct kobject *kobj = sq_kobject[cpu]; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36338a382ae5dd4f4d04e3046816b0a41836094e538Greg Kroah-Hartman kobject_put(kobj); 364d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return 0; 365d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt} 366d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 3678a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sieversstatic struct subsys_interface sq_interface = { 36833dc5c1000c193084a70ffd8f3bd9c67d19f9159Paul Mundt .name = "sq", 3698a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers .subsys = &cpu_subsys, 3708a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers .add_dev = sq_dev_add, 37133dc5c1000c193084a70ffd8f3bd9c67d19f9159Paul Mundt .remove_dev = sq_dev_remove, 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sq_api_init(void) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 376d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT; 377d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG; 378d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt int ret = -ENOMEM; 379d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE "sq: Registering store queue API.\n"); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 382d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_cache = kmem_cache_create("store_queue_cache", 38320c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt sizeof(struct sq_mapping), 0, 0, NULL); 384d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!sq_cache)) 385d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return ret; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 387d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt sq_bitmap = kzalloc(size, GFP_KERNEL); 388d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(!sq_bitmap)) 389d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt goto out; 390d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 3918a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers ret = subsys_interface_register(&sq_interface); 392d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt if (unlikely(ret != 0)) 393d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt goto out; 394d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 395d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt return 0; 396d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt 397d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundtout: 398d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kfree(sq_bitmap); 399d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kmem_cache_destroy(sq_cache); 400757be186129b674e3a0146a4bc1861ed0744cd95Neil Horman 401757be186129b674e3a0146a4bc1861ed0744cd95Neil Horman return ret; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sq_api_exit(void) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4068a25a2fd126c621f44f3aeaef80d51f00fc11639Kay Sievers subsys_interface_unregister(&sq_interface); 407d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kfree(sq_bitmap); 408d7c30c682a278abe1a52db83f69efec1a9d8f8c2Paul Mundt kmem_cache_destroy(sq_cache); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sq_api_init); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sq_api_exit); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues"); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 417