1 // SPDX-License-Identifier: GPL-2.0-only 2 /* flash.c: Allow mmap access to the OBP Flash, for OBP updates. 3 * 4 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 5 */ 6 7 #include <linux/module.h> 8 #include <linux/types.h> 9 #include <linux/errno.h> 10 #include <linux/miscdevice.h> 11 #include <linux/fcntl.h> 12 #include <linux/poll.h> 13 #include <linux/mutex.h> 14 #include <linux/spinlock.h> 15 #include <linux/mm.h> 16 #include <linux/of.h> 17 #include <linux/of_device.h> 18 19 #include <linux/uaccess.h> 20 #include <asm/pgtable.h> 21 #include <asm/io.h> 22 #include <asm/upa.h> 23 24 static DEFINE_MUTEX(flash_mutex); 25 static DEFINE_SPINLOCK(flash_lock); 26 static struct { 27 unsigned long read_base; /* Physical read address */ 28 unsigned long write_base; /* Physical write address */ 29 unsigned long read_size; /* Size of read area */ 30 unsigned long write_size; /* Size of write area */ 31 unsigned long busy; /* In use? */ 32 } flash; 33 34 #define FLASH_MINOR 152 35 36 static int 37 flash_mmap(struct file *file, struct vm_area_struct *vma) 38 { 39 unsigned long addr; 40 unsigned long size; 41 42 spin_lock(&flash_lock); 43 if (flash.read_base == flash.write_base) { 44 addr = flash.read_base; 45 size = flash.read_size; 46 } else { 47 if ((vma->vm_flags & VM_READ) && 48 (vma->vm_flags & VM_WRITE)) { 49 spin_unlock(&flash_lock); 50 return -EINVAL; 51 } 52 if (vma->vm_flags & VM_READ) { 53 addr = flash.read_base; 54 size = flash.read_size; 55 } else if (vma->vm_flags & VM_WRITE) { 56 addr = flash.write_base; 57 size = flash.write_size; 58 } else { 59 spin_unlock(&flash_lock); 60 return -ENXIO; 61 } 62 } 63 spin_unlock(&flash_lock); 64 65 if ((vma->vm_pgoff << PAGE_SHIFT) > size) 66 return -ENXIO; 67 addr = vma->vm_pgoff + (addr >> PAGE_SHIFT); 68 69 if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size) 70 size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)); 71 72 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 73 74 if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot)) 75 return -EAGAIN; 76 77 return 0; 78 } 79 80 static long long 81 flash_llseek(struct file *file, long long offset, int origin) 82 { 83 mutex_lock(&flash_mutex); 84 switch (origin) { 85 case 0: 86 file->f_pos = offset; 87 break; 88 case 1: 89 file->f_pos += offset; 90 if (file->f_pos > flash.read_size) 91 file->f_pos = flash.read_size; 92 break; 93 case 2: 94 file->f_pos = flash.read_size; 95 break; 96 default: 97 mutex_unlock(&flash_mutex); 98 return -EINVAL; 99 } 100 mutex_unlock(&flash_mutex); 101 return file->f_pos; 102 } 103 104 static ssize_t 105 flash_read(struct file * file, char __user * buf, 106 size_t count, loff_t *ppos) 107 { 108 loff_t p = *ppos; 109 int i; 110 111 if (count > flash.read_size - p) 112 count = flash.read_size - p; 113 114 for (i = 0; i < count; i++) { 115 u8 data = upa_readb(flash.read_base + p + i); 116 if (put_user(data, buf)) 117 return -EFAULT; 118 buf++; 119 } 120 121 *ppos += count; 122 return count; 123 } 124 125 static int 126 flash_open(struct inode *inode, struct file *file) 127 { 128 mutex_lock(&flash_mutex); 129 if (test_and_set_bit(0, (void *)&flash.busy) != 0) { 130 mutex_unlock(&flash_mutex); 131 return -EBUSY; 132 } 133 134 mutex_unlock(&flash_mutex); 135 return 0; 136 } 137 138 static int 139 flash_release(struct inode *inode, struct file *file) 140 { 141 spin_lock(&flash_lock); 142 flash.busy = 0; 143 spin_unlock(&flash_lock); 144 145 return 0; 146 } 147 148 static const struct file_operations flash_fops = { 149 /* no write to the Flash, use mmap 150 * and play flash dependent tricks. 151 */ 152 .owner = THIS_MODULE, 153 .llseek = flash_llseek, 154 .read = flash_read, 155 .mmap = flash_mmap, 156 .open = flash_open, 157 .release = flash_release, 158 }; 159 160 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; 161 162 static int flash_probe(struct platform_device *op) 163 { 164 struct device_node *dp = op->dev.of_node; 165 struct device_node *parent; 166 167 parent = dp->parent; 168 169 if (!of_node_name_eq(parent, "sbus") && 170 !of_node_name_eq(parent, "sbi") && 171 !of_node_name_eq(parent, "ebus")) 172 return -ENODEV; 173 174 flash.read_base = op->resource[0].start; 175 flash.read_size = resource_size(&op->resource[0]); 176 if (op->resource[1].flags) { 177 flash.write_base = op->resource[1].start; 178 flash.write_size = resource_size(&op->resource[1]); 179 } else { 180 flash.write_base = op->resource[0].start; 181 flash.write_size = resource_size(&op->resource[0]); 182 } 183 flash.busy = 0; 184 185 printk(KERN_INFO "%pOF: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", 186 op->dev.of_node, 187 flash.read_base, flash.read_size, 188 flash.write_base, flash.write_size); 189 190 return misc_register(&flash_dev); 191 } 192 193 static int flash_remove(struct platform_device *op) 194 { 195 misc_deregister(&flash_dev); 196 197 return 0; 198 } 199 200 static const struct of_device_id flash_match[] = { 201 { 202 .name = "flashprom", 203 }, 204 {}, 205 }; 206 MODULE_DEVICE_TABLE(of, flash_match); 207 208 static struct platform_driver flash_driver = { 209 .driver = { 210 .name = "flash", 211 .of_match_table = flash_match, 212 }, 213 .probe = flash_probe, 214 .remove = flash_remove, 215 }; 216 217 module_platform_driver(flash_driver); 218 219 MODULE_LICENSE("GPL"); 220