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