Merge remote-tracking branches 'asoc/topic/cs47l24', 'asoc/topic/cx20442', 'asoc...
[sfrench/cifs-2.6.git] / drivers / firmware / google / vpd.c
1 /*
2  * vpd.c
3  *
4  * Driver for exporting VPD content to sysfs.
5  *
6  * Copyright 2017 Google Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License v2.0 as published by
10  * the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/ctype.h>
19 #include <linux/init.h>
20 #include <linux/io.h>
21 #include <linux/kernel.h>
22 #include <linux/kobject.h>
23 #include <linux/list.h>
24 #include <linux/module.h>
25 #include <linux/of_address.h>
26 #include <linux/platform_device.h>
27 #include <linux/slab.h>
28 #include <linux/sysfs.h>
29
30 #include "coreboot_table.h"
31 #include "vpd_decode.h"
32
33 #define CB_TAG_VPD      0x2c
34 #define VPD_CBMEM_MAGIC 0x43524f53
35
36 static struct kobject *vpd_kobj;
37
38 struct vpd_cbmem {
39         u32 magic;
40         u32 version;
41         u32 ro_size;
42         u32 rw_size;
43         u8  blob[0];
44 };
45
46 struct vpd_section {
47         bool enabled;
48         const char *name;
49         char *raw_name;                /* the string name_raw */
50         struct kobject *kobj;          /* vpd/name directory */
51         char *baseaddr;
52         struct bin_attribute bin_attr; /* vpd/name_raw bin_attribute */
53         struct list_head attribs;      /* key/value in vpd_attrib_info list */
54 };
55
56 struct vpd_attrib_info {
57         char *key;
58         const char *value;
59         struct bin_attribute bin_attr;
60         struct list_head list;
61 };
62
63 static struct vpd_section ro_vpd;
64 static struct vpd_section rw_vpd;
65
66 static ssize_t vpd_attrib_read(struct file *filp, struct kobject *kobp,
67                                struct bin_attribute *bin_attr, char *buf,
68                                loff_t pos, size_t count)
69 {
70         struct vpd_attrib_info *info = bin_attr->private;
71
72         return memory_read_from_buffer(buf, count, &pos, info->value,
73                                        info->bin_attr.size);
74 }
75
76 /*
77  * vpd_section_check_key_name()
78  *
79  * The VPD specification supports only [a-zA-Z0-9_]+ characters in key names but
80  * old firmware versions may have entries like "S/N" which are problematic when
81  * exporting them as sysfs attributes. These keys present in old firmwares are
82  * ignored.
83  *
84  * Returns VPD_OK for a valid key name, VPD_FAIL otherwise.
85  *
86  * @key: The key name to check
87  * @key_len: key name length
88  */
89 static int vpd_section_check_key_name(const u8 *key, s32 key_len)
90 {
91         int c;
92
93         while (key_len-- > 0) {
94                 c = *key++;
95
96                 if (!isalnum(c) && c != '_')
97                         return VPD_FAIL;
98         }
99
100         return VPD_OK;
101 }
102
103 static int vpd_section_attrib_add(const u8 *key, s32 key_len,
104                                   const u8 *value, s32 value_len,
105                                   void *arg)
106 {
107         int ret;
108         struct vpd_section *sec = arg;
109         struct vpd_attrib_info *info;
110
111         /*
112          * Return VPD_OK immediately to decode next entry if the current key
113          * name contains invalid characters.
114          */
115         if (vpd_section_check_key_name(key, key_len) != VPD_OK)
116                 return VPD_OK;
117
118         info = kzalloc(sizeof(*info), GFP_KERNEL);
119         if (!info)
120                 return -ENOMEM;
121
122         info->key = kstrndup(key, key_len, GFP_KERNEL);
123         if (!info->key) {
124                 ret = -ENOMEM;
125                 goto free_info;
126         }
127
128         sysfs_bin_attr_init(&info->bin_attr);
129         info->bin_attr.attr.name = info->key;
130         info->bin_attr.attr.mode = 0444;
131         info->bin_attr.size = value_len;
132         info->bin_attr.read = vpd_attrib_read;
133         info->bin_attr.private = info;
134
135         info->value = value;
136
137         INIT_LIST_HEAD(&info->list);
138
139         ret = sysfs_create_bin_file(sec->kobj, &info->bin_attr);
140         if (ret)
141                 goto free_info_key;
142
143         list_add_tail(&info->list, &sec->attribs);
144         return 0;
145
146 free_info_key:
147         kfree(info->key);
148 free_info:
149         kfree(info);
150
151         return ret;
152 }
153
154 static void vpd_section_attrib_destroy(struct vpd_section *sec)
155 {
156         struct vpd_attrib_info *info;
157         struct vpd_attrib_info *temp;
158
159         list_for_each_entry_safe(info, temp, &sec->attribs, list) {
160                 sysfs_remove_bin_file(sec->kobj, &info->bin_attr);
161                 kfree(info->key);
162                 kfree(info);
163         }
164 }
165
166 static ssize_t vpd_section_read(struct file *filp, struct kobject *kobp,
167                                 struct bin_attribute *bin_attr, char *buf,
168                                 loff_t pos, size_t count)
169 {
170         struct vpd_section *sec = bin_attr->private;
171
172         return memory_read_from_buffer(buf, count, &pos, sec->baseaddr,
173                                        sec->bin_attr.size);
174 }
175
176 static int vpd_section_create_attribs(struct vpd_section *sec)
177 {
178         s32 consumed;
179         int ret;
180
181         consumed = 0;
182         do {
183                 ret = vpd_decode_string(sec->bin_attr.size, sec->baseaddr,
184                                         &consumed, vpd_section_attrib_add, sec);
185         } while (ret == VPD_OK);
186
187         return 0;
188 }
189
190 static int vpd_section_init(const char *name, struct vpd_section *sec,
191                             phys_addr_t physaddr, size_t size)
192 {
193         int err;
194
195         sec->baseaddr = memremap(physaddr, size, MEMREMAP_WB);
196         if (!sec->baseaddr)
197                 return -ENOMEM;
198
199         sec->name = name;
200
201         /* We want to export the raw partion with name ${name}_raw */
202         sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name);
203         if (!sec->raw_name) {
204                 err = -ENOMEM;
205                 goto err_memunmap;
206         }
207
208         sysfs_bin_attr_init(&sec->bin_attr);
209         sec->bin_attr.attr.name = sec->raw_name;
210         sec->bin_attr.attr.mode = 0444;
211         sec->bin_attr.size = size;
212         sec->bin_attr.read = vpd_section_read;
213         sec->bin_attr.private = sec;
214
215         err = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr);
216         if (err)
217                 goto err_free_raw_name;
218
219         sec->kobj = kobject_create_and_add(name, vpd_kobj);
220         if (!sec->kobj) {
221                 err = -EINVAL;
222                 goto err_sysfs_remove;
223         }
224
225         INIT_LIST_HEAD(&sec->attribs);
226         vpd_section_create_attribs(sec);
227
228         sec->enabled = true;
229
230         return 0;
231
232 err_sysfs_remove:
233         sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
234 err_free_raw_name:
235         kfree(sec->raw_name);
236 err_memunmap:
237         memunmap(sec->baseaddr);
238         return err;
239 }
240
241 static int vpd_section_destroy(struct vpd_section *sec)
242 {
243         if (sec->enabled) {
244                 vpd_section_attrib_destroy(sec);
245                 kobject_put(sec->kobj);
246                 sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
247                 kfree(sec->raw_name);
248                 memunmap(sec->baseaddr);
249         }
250
251         return 0;
252 }
253
254 static int vpd_sections_init(phys_addr_t physaddr)
255 {
256         struct vpd_cbmem __iomem *temp;
257         struct vpd_cbmem header;
258         int ret = 0;
259
260         temp = memremap(physaddr, sizeof(struct vpd_cbmem), MEMREMAP_WB);
261         if (!temp)
262                 return -ENOMEM;
263
264         memcpy_fromio(&header, temp, sizeof(struct vpd_cbmem));
265         memunmap(temp);
266
267         if (header.magic != VPD_CBMEM_MAGIC)
268                 return -ENODEV;
269
270         if (header.ro_size) {
271                 ret = vpd_section_init("ro", &ro_vpd,
272                                        physaddr + sizeof(struct vpd_cbmem),
273                                        header.ro_size);
274                 if (ret)
275                         return ret;
276         }
277
278         if (header.rw_size) {
279                 ret = vpd_section_init("rw", &rw_vpd,
280                                        physaddr + sizeof(struct vpd_cbmem) +
281                                        header.ro_size, header.rw_size);
282                 if (ret)
283                         return ret;
284         }
285
286         return 0;
287 }
288
289 static int vpd_probe(struct platform_device *pdev)
290 {
291         int ret;
292         struct lb_cbmem_ref entry;
293
294         ret = coreboot_table_find(CB_TAG_VPD, &entry, sizeof(entry));
295         if (ret)
296                 return ret;
297
298         vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
299         if (!vpd_kobj)
300                 return -ENOMEM;
301
302         ret = vpd_sections_init(entry.cbmem_addr);
303         if (ret) {
304                 kobject_put(vpd_kobj);
305                 return ret;
306         }
307
308         return 0;
309 }
310
311 static int vpd_remove(struct platform_device *pdev)
312 {
313         vpd_section_destroy(&ro_vpd);
314         vpd_section_destroy(&rw_vpd);
315
316         kobject_put(vpd_kobj);
317
318         return 0;
319 }
320
321 static struct platform_driver vpd_driver = {
322         .probe = vpd_probe,
323         .remove = vpd_remove,
324         .driver = {
325                 .name = "vpd",
326         },
327 };
328
329 static struct platform_device *vpd_pdev;
330
331 static int __init vpd_platform_init(void)
332 {
333         int ret;
334
335         ret = platform_driver_register(&vpd_driver);
336         if (ret)
337                 return ret;
338
339         vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0);
340         if (IS_ERR(vpd_pdev)) {
341                 platform_driver_unregister(&vpd_driver);
342                 return PTR_ERR(vpd_pdev);
343         }
344
345         return 0;
346 }
347
348 static void __exit vpd_platform_exit(void)
349 {
350         platform_device_unregister(vpd_pdev);
351         platform_driver_unregister(&vpd_driver);
352 }
353
354 module_init(vpd_platform_init);
355 module_exit(vpd_platform_exit);
356
357 MODULE_AUTHOR("Google, Inc.");
358 MODULE_LICENSE("GPL");