Commit a18609a1 authored by Hiroshi DOYU's avatar Hiroshi DOYU Committed by Tony Lindgren

OMAP: MMU: Fix inconsistency to unregister device MMU

There was a problem that kernel counldn't find struct device for
device MMU when unregistering it for class. This is because device
MMUs are the pseudo devices and they were not created when registering
into MMU class. This patch will create struct device when registering
device MMU into class and will fix the problem that "dspctl cleanup"
encountered kernel Oops.
Signed-off-by: default avatarHiroshi DOYU <Hiroshi.DOYU@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 1fda54d1
...@@ -198,7 +198,7 @@ static int omap1_mmu_startup(struct omap_mmu *mmu) ...@@ -198,7 +198,7 @@ static int omap1_mmu_startup(struct omap_mmu *mmu)
{ {
dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0); dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
if (dspvect_page == NULL) { if (dspvect_page == NULL) {
dev_err(&mmu->dev, "MMU %s: failed to allocate memory " dev_err(mmu->dev, "MMU %s: failed to allocate memory "
"for vector table\n", mmu->name); "for vector table\n", mmu->name);
return -ENOMEM; return -ENOMEM;
} }
...@@ -240,7 +240,7 @@ omap1_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry) ...@@ -240,7 +240,7 @@ omap1_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
struct cam_ram_regset *cr; struct cam_ram_regset *cr;
if (entry->va & ~(get_cam_va_mask(entry->pgsz))) { if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
dev_err(&mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on" dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
" an aligned boundary\n", mmu->name, entry->va); " an aligned boundary\n", mmu->name, entry->va);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -143,7 +143,7 @@ static int omap2_mmu_startup(struct omap_mmu *mmu) ...@@ -143,7 +143,7 @@ static int omap2_mmu_startup(struct omap_mmu *mmu)
dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0); dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
if (dspvect_page == NULL) { if (dspvect_page == NULL) {
dev_err(&mmu->dev, "MMU %s: failed to allocate memory " dev_err(mmu->dev, "MMU %s: failed to allocate memory "
"for vector table\n", mmu->name); "for vector table\n", mmu->name);
return -ENOMEM; return -ENOMEM;
} }
...@@ -256,7 +256,7 @@ omap2_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry) ...@@ -256,7 +256,7 @@ omap2_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
struct cam_ram_regset *cr; struct cam_ram_regset *cr;
if (entry->va & ~(get_cam_va_mask(entry->pgsz))) { if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
dev_err(&mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on" dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
" an aligned boundary\n", mmu->name, entry->va); " an aligned boundary\n", mmu->name, entry->va);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -106,14 +106,14 @@ int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size) ...@@ -106,14 +106,14 @@ int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size)
/* alignment check */ /* alignment check */
if (!is_aligned(size, SZ_64K)) { if (!is_aligned(size, SZ_64K)) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: size(0x%lx) is not multiple of 64KB.\n", "MMU %s: size(0x%lx) is not multiple of 64KB.\n",
mmu->name, size); mmu->name, size);
return -EINVAL; return -EINVAL;
} }
if (size > (1 << mmu->addrspace)) { if (size > (1 << mmu->addrspace)) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: size(0x%lx) is larger than external device " "MMU %s: size(0x%lx) is larger than external device "
" memory space size (0x%x.\n", mmu->name, size, " memory space size (0x%x.\n", mmu->name, size,
(1 << mmu->addrspace)); (1 << mmu->addrspace));
...@@ -199,7 +199,7 @@ int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt, ...@@ -199,7 +199,7 @@ int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt,
pte_t *ptep; pte_t *ptep;
int prot_pmd, prot_pte; int prot_pmd, prot_pte;
dev_dbg(&mmu->dev, dev_dbg(mmu->dev,
"MMU %s: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n", "MMU %s: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
mmu->name, virt, phys, size); mmu->name, virt, phys, size);
...@@ -236,7 +236,7 @@ void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt, ...@@ -236,7 +236,7 @@ void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt,
pmd_t *pmdp; pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
dev_dbg(&mmu->dev, dev_dbg(mmu->dev,
"MMU %s: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n", "MMU %s: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n",
mmu->name, virt, size); mmu->name, virt, size);
...@@ -599,7 +599,7 @@ int omap_mmu_load_tlb_entry(struct omap_mmu *mmu, ...@@ -599,7 +599,7 @@ int omap_mmu_load_tlb_entry(struct omap_mmu *mmu,
found_victim: found_victim:
/* The last entry cannot be locked? */ /* The last entry cannot be locked? */
if (lock.victim == (mmu->nr_tlb_entries - 1)) { if (lock.victim == (mmu->nr_tlb_entries - 1)) {
dev_err(&mmu->dev, "MMU %s: TLB is full.\n", mmu->name); dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
return -EBUSY; return -EBUSY;
} }
...@@ -744,19 +744,19 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr, ...@@ -744,19 +744,19 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr,
* alignment check * alignment check
*/ */
if (!is_aligned(size, MINIMUM_PAGESZ)) { if (!is_aligned(size, MINIMUM_PAGESZ)) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: size(0x%lx) is not multiple of 4KB.\n", "MMU %s: size(0x%lx) is not multiple of 4KB.\n",
mmu->name, size); mmu->name, size);
return -EINVAL; return -EINVAL;
} }
if (!is_aligned(devadr, MINIMUM_PAGESZ)) { if (!is_aligned(devadr, MINIMUM_PAGESZ)) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: external device address(0x%lx) is not" "MMU %s: external device address(0x%lx) is not"
" aligned.\n", mmu->name, devadr); " aligned.\n", mmu->name, devadr);
return -EINVAL; return -EINVAL;
} }
if (!is_aligned(padr, MINIMUM_PAGESZ)) { if (!is_aligned(padr, MINIMUM_PAGESZ)) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: physical address(0x%lx) is not aligned.\n", "MMU %s: physical address(0x%lx) is not aligned.\n",
mmu->name, padr); mmu->name, padr);
return -EINVAL; return -EINVAL;
...@@ -765,7 +765,7 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr, ...@@ -765,7 +765,7 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr,
/* address validity check */ /* address validity check */
if ((devadr < mmu->memsize) || if ((devadr < mmu->memsize) ||
(devadr >= (1 << mmu->addrspace))) { (devadr >= (1 << mmu->addrspace))) {
dev_err(&mmu->dev, dev_err(mmu->dev,
"MMU %s: illegal address/size for %s().\n", "MMU %s: illegal address/size for %s().\n",
mmu->name, __FUNCTION__); mmu->name, __FUNCTION__);
return -EINVAL; return -EINVAL;
...@@ -782,7 +782,7 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr, ...@@ -782,7 +782,7 @@ int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr,
mapsize = 1 << (tmp_ent->order + PAGE_SHIFT); mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
if ((_vadr + size > tmp_ent->vadr) && if ((_vadr + size > tmp_ent->vadr) &&
(_vadr < tmp_ent->vadr + mapsize)) { (_vadr < tmp_ent->vadr + mapsize)) {
dev_err(&mmu->dev, "MMU %s: exmap page overlap!\n", dev_err(mmu->dev, "MMU %s: exmap page overlap!\n",
mmu->name); mmu->name);
up_write(&mmu->exmap_sem); up_write(&mmu->exmap_sem);
return -EINVAL; return -EINVAL;
...@@ -796,7 +796,7 @@ start: ...@@ -796,7 +796,7 @@ start:
if (!mmu->exmap_tbl[idx].valid) if (!mmu->exmap_tbl[idx].valid)
goto found_free; goto found_free;
dev_err(&mmu->dev, "MMU %s: TLB is full.\n", mmu->name); dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
status = -EBUSY; status = -EBUSY;
goto fail; goto fail;
...@@ -900,7 +900,7 @@ static unsigned long unmap_free_arm(struct omap_mmu *mmu, ...@@ -900,7 +900,7 @@ static unsigned long unmap_free_arm(struct omap_mmu *mmu,
/* freeing allocated memory */ /* freeing allocated memory */
if (ent->type == EXMAP_TYPE_MEM) { if (ent->type == EXMAP_TYPE_MEM) {
omap_mmu_free_pages((unsigned long)ent->buf, ent->order); omap_mmu_free_pages((unsigned long)ent->buf, ent->order);
dev_dbg(&mmu->dev, "MMU %s: freeing 0x%lx bytes @ adr 0x%8p\n", dev_dbg(mmu->dev, "MMU %s: freeing 0x%lx bytes @ adr 0x%8p\n",
mmu->name, size, ent->buf); mmu->name, size, ent->buf);
} }
...@@ -926,13 +926,13 @@ int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long devadr) ...@@ -926,13 +926,13 @@ int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long devadr)
goto found_map; goto found_map;
} }
up_write(&mmu->exmap_sem); up_write(&mmu->exmap_sem);
dev_warn(&mmu->dev, "MMU %s: address %06lx not found in exmap_tbl.\n", dev_warn(mmu->dev, "MMU %s: address %06lx not found in exmap_tbl.\n",
mmu->name, devadr); mmu->name, devadr);
return -EINVAL; return -EINVAL;
found_map: found_map:
if (ent->usecount > 0) { if (ent->usecount > 0) {
dev_err(&mmu->dev, "MMU %s: exmap reference count is not 0.\n" dev_err(mmu->dev, "MMU %s: exmap reference count is not 0.\n"
" idx=%d, vadr=%p, order=%d, usecount=%d\n", " idx=%d, vadr=%p, order=%d, usecount=%d\n",
mmu->name, idx, ent->vadr, ent->order, ent->usecount); mmu->name, idx, ent->vadr, ent->order, ent->usecount);
up_write(&mmu->exmap_sem); up_write(&mmu->exmap_sem);
...@@ -960,7 +960,7 @@ found_map: ...@@ -960,7 +960,7 @@ found_map:
if (ent->vadr == vadr) if (ent->vadr == vadr)
goto found_map; /* continue */ goto found_map; /* continue */
dev_err(&mmu->dev, "MMU %s: illegal exmap_tbl grouping!\n" dev_err(mmu->dev, "MMU %s: illegal exmap_tbl grouping!\n"
"expected vadr = %p, exmap_tbl[%d].vadr = %p\n", "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
mmu->name, vadr, idx, ent->vadr); mmu->name, vadr, idx, ent->vadr);
up_write(&mmu->exmap_sem); up_write(&mmu->exmap_sem);
...@@ -1083,7 +1083,7 @@ static int omap_mmu_init(struct omap_mmu *mmu) ...@@ -1083,7 +1083,7 @@ static int omap_mmu_init(struct omap_mmu *mmu)
ret = request_irq(mmu->irq, omap_mmu_interrupt, IRQF_DISABLED, ret = request_irq(mmu->irq, omap_mmu_interrupt, IRQF_DISABLED,
mmu->name, mmu); mmu->name, mmu);
if (ret < 0) { if (ret < 0) {
dev_err(&mmu->dev, "MMU %s: failed to register MMU interrupt:" dev_err(mmu->dev, "MMU %s: failed to register MMU interrupt:"
" %d\n", mmu->name, ret); " %d\n", mmu->name, ret);
goto fail; goto fail;
} }
...@@ -1175,7 +1175,7 @@ static ssize_t exmem_read(struct omap_mmu *mmu, char *buf, size_t count, ...@@ -1175,7 +1175,7 @@ static ssize_t exmem_read(struct omap_mmu *mmu, char *buf, size_t count,
void *vadr = omap_mmu_to_virt(mmu, p); void *vadr = omap_mmu_to_virt(mmu, p);
if (!exmap_valid(mmu, vadr, count)) { if (!exmap_valid(mmu, vadr, count)) {
dev_err(&mmu->dev, "MMU %s: external device address %08lx / " dev_err(mmu->dev, "MMU %s: external device address %08lx / "
"size %08x is not valid!\n", mmu->name, p, count); "size %08x is not valid!\n", mmu->name, p, count);
return -EFAULT; return -EFAULT;
} }
...@@ -1242,7 +1242,7 @@ static ssize_t exmem_write(struct omap_mmu *mmu, char *buf, size_t count, ...@@ -1242,7 +1242,7 @@ static ssize_t exmem_write(struct omap_mmu *mmu, char *buf, size_t count,
void *vadr = omap_mmu_to_virt(mmu, p); void *vadr = omap_mmu_to_virt(mmu, p);
if (!exmap_valid(mmu, vadr, count)) { if (!exmap_valid(mmu, vadr, count)) {
dev_err(&mmu->dev, "MMU %s: external device address %08lx " dev_err(mmu->dev, "MMU %s: external device address %08lx "
"/ size %08x is not valid!\n", mmu->name, p, count); "/ size %08x is not valid!\n", mmu->name, p, count);
return -EFAULT; return -EFAULT;
} }
...@@ -1294,7 +1294,7 @@ ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu, ...@@ -1294,7 +1294,7 @@ ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu,
struct bin_attribute *attr, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count) char *buf, loff_t offset, size_t count)
{ {
return omap_mmu_mem_read(&mmu->dev.kobj, attr, buf, offset, count); return omap_mmu_mem_read(&mmu->dev->kobj, attr, buf, offset, count);
} }
EXPORT_SYMBOL_GPL(__omap_mmu_mem_read); EXPORT_SYMBOL_GPL(__omap_mmu_mem_read);
...@@ -1302,7 +1302,7 @@ ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu, ...@@ -1302,7 +1302,7 @@ ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu,
struct bin_attribute *attr, struct bin_attribute *attr,
char *buf, loff_t offset, size_t count) char *buf, loff_t offset, size_t count)
{ {
return omap_mmu_mem_write(&mmu->dev.kobj, attr, buf, offset, count); return omap_mmu_mem_write(&mmu->dev->kobj, attr, buf, offset, count);
} }
EXPORT_SYMBOL_GPL(__omap_mmu_mem_write); EXPORT_SYMBOL_GPL(__omap_mmu_mem_write);
...@@ -1464,11 +1464,12 @@ int omap_mmu_register(struct omap_mmu *mmu) ...@@ -1464,11 +1464,12 @@ int omap_mmu_register(struct omap_mmu *mmu)
{ {
int ret; int ret;
mmu->dev.class = &omap_mmu_class; mmu->dev = device_create(&omap_mmu_class, NULL, 0, "%s", mmu->name);
strlcpy(mmu->dev.bus_id, mmu->name, KOBJ_NAME_LEN); if (unlikely(IS_ERR(mmu->dev)))
dev_set_drvdata(&mmu->dev, mmu); return PTR_ERR(mmu->dev);
dev_set_drvdata(mmu->dev, mmu);
mmu->exmap_tbl = kzalloc(sizeof(struct exmap_tbl) * mmu->nr_tlb_entries, mmu->exmap_tbl = kcalloc(mmu->nr_tlb_entries, sizeof(struct exmap_tbl),
GFP_KERNEL); GFP_KERNEL);
if (!mmu->exmap_tbl) if (!mmu->exmap_tbl)
return -ENOMEM; return -ENOMEM;
...@@ -1479,47 +1480,41 @@ int omap_mmu_register(struct omap_mmu *mmu) ...@@ -1479,47 +1480,41 @@ int omap_mmu_register(struct omap_mmu *mmu)
goto err_mm_alloc; goto err_mm_alloc;
} }
ret = device_register(&mmu->dev);
if (unlikely(ret))
goto err_dev_register;
init_rwsem(&mmu->exmap_sem); init_rwsem(&mmu->exmap_sem);
ret = omap_mmu_init(mmu); ret = omap_mmu_init(mmu);
if (unlikely(ret)) if (unlikely(ret))
goto err_mmu_init; goto err_mmu_init;
ret = device_create_file(&mmu->dev, &dev_attr_mmu); ret = device_create_file(mmu->dev, &dev_attr_mmu);
if (unlikely(ret)) if (unlikely(ret))
goto err_dev_create_mmu; goto err_dev_create_mmu;
ret = device_create_file(&mmu->dev, &dev_attr_exmap); ret = device_create_file(mmu->dev, &dev_attr_exmap);
if (unlikely(ret)) if (unlikely(ret))
goto err_dev_create_exmap; goto err_dev_create_exmap;
if (likely(mmu->membase)) { if (likely(mmu->membase)) {
dev_attr_mem.size = mmu->memsize; dev_attr_mem.size = mmu->memsize;
ret = device_create_bin_file(&mmu->dev, ret = device_create_bin_file(mmu->dev,
&dev_attr_mem); &dev_attr_mem);
if (unlikely(ret)) if (unlikely(ret))
goto err_bin_create_mem; goto err_bin_create_mem;
} }
return 0; return 0;
err_bin_create_mem: err_bin_create_mem:
device_remove_file(&mmu->dev, &dev_attr_exmap); device_remove_file(mmu->dev, &dev_attr_exmap);
err_dev_create_exmap: err_dev_create_exmap:
device_remove_file(&mmu->dev, &dev_attr_mmu); device_remove_file(mmu->dev, &dev_attr_mmu);
err_dev_create_mmu: err_dev_create_mmu:
omap_mmu_shutdown(mmu); omap_mmu_shutdown(mmu);
err_mmu_init: err_mmu_init:
device_unregister(&mmu->dev);
err_dev_register:
kfree(mmu->twl_mm); kfree(mmu->twl_mm);
mmu->twl_mm = NULL; mmu->twl_mm = NULL;
err_mm_alloc: err_mm_alloc:
kfree(mmu->exmap_tbl); kfree(mmu->exmap_tbl);
mmu->exmap_tbl = NULL; mmu->exmap_tbl = NULL;
device_unregister(mmu->dev);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(omap_mmu_register); EXPORT_SYMBOL_GPL(omap_mmu_register);
...@@ -1529,12 +1524,13 @@ void omap_mmu_unregister(struct omap_mmu *mmu) ...@@ -1529,12 +1524,13 @@ void omap_mmu_unregister(struct omap_mmu *mmu)
omap_mmu_shutdown(mmu); omap_mmu_shutdown(mmu);
omap_mmu_kmem_release(); omap_mmu_kmem_release();
device_remove_file(&mmu->dev, &dev_attr_mmu); device_remove_file(mmu->dev, &dev_attr_mmu);
device_remove_file(&mmu->dev, &dev_attr_exmap); device_remove_file(mmu->dev, &dev_attr_exmap);
if (likely(mmu->membase)) if (likely(mmu->membase))
device_remove_bin_file(&mmu->dev, device_remove_bin_file(mmu->dev, &dev_attr_mem);
&dev_attr_mem);
device_unregister(mmu->dev);
kfree(mmu->exmap_tbl); kfree(mmu->exmap_tbl);
mmu->exmap_tbl = NULL; mmu->exmap_tbl = NULL;
...@@ -1543,8 +1539,6 @@ void omap_mmu_unregister(struct omap_mmu *mmu) ...@@ -1543,8 +1539,6 @@ void omap_mmu_unregister(struct omap_mmu *mmu)
__mmdrop(mmu->twl_mm); __mmdrop(mmu->twl_mm);
mmu->twl_mm = NULL; mmu->twl_mm = NULL;
} }
device_unregister(&mmu->dev);
} }
EXPORT_SYMBOL_GPL(omap_mmu_unregister); EXPORT_SYMBOL_GPL(omap_mmu_unregister);
......
...@@ -104,7 +104,7 @@ struct omap_mmu { ...@@ -104,7 +104,7 @@ struct omap_mmu {
enum omap_mmu_type type; enum omap_mmu_type type;
struct device dev; struct device *dev;
struct rw_semaphore exmap_sem; struct rw_semaphore exmap_sem;
struct exmap_tbl *exmap_tbl; struct exmap_tbl *exmap_tbl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment