4 * Driver for exporting VPD content to sysfs.
6 * Copyright 2017 Google Inc.
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.
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.
18 #include <linux/ctype.h>
19 #include <linux/init.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>
30 #include "coreboot_table.h"
31 #include "vpd_decode.h"
33 #define CB_TAG_VPD 0x2c
34 #define VPD_CBMEM_MAGIC 0x43524f53
36 static struct kobject
*vpd_kobj
;
49 char *raw_name
; /* the string name_raw */
50 struct kobject
*kobj
; /* vpd/name directory */
52 struct bin_attribute bin_attr
; /* vpd/name_raw bin_attribute */
53 struct list_head attribs
; /* key/value in vpd_attrib_info list */
56 struct vpd_attrib_info
{
59 struct bin_attribute bin_attr
;
60 struct list_head list
;
63 static struct vpd_section ro_vpd
;
64 static struct vpd_section rw_vpd
;
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
)
70 struct vpd_attrib_info
*info
= bin_attr
->private;
72 return memory_read_from_buffer(buf
, count
, &pos
, info
->value
,
77 * vpd_section_check_key_name()
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
84 * Returns VPD_OK for a valid key name, VPD_FAIL otherwise.
86 * @key: The key name to check
87 * @key_len: key name length
89 static int vpd_section_check_key_name(const u8
*key
, s32 key_len
)
93 while (key_len
-- > 0) {
96 if (!isalnum(c
) && c
!= '_')
103 static int vpd_section_attrib_add(const u8
*key
, s32 key_len
,
104 const u8
*value
, s32 value_len
,
108 struct vpd_section
*sec
= arg
;
109 struct vpd_attrib_info
*info
;
112 * Return VPD_OK immediately to decode next entry if the current key
113 * name contains invalid characters.
115 if (vpd_section_check_key_name(key
, key_len
) != VPD_OK
)
118 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
119 info
->key
= kzalloc(key_len
+ 1, GFP_KERNEL
);
123 memcpy(info
->key
, key
, key_len
);
125 sysfs_bin_attr_init(&info
->bin_attr
);
126 info
->bin_attr
.attr
.name
= info
->key
;
127 info
->bin_attr
.attr
.mode
= 0444;
128 info
->bin_attr
.size
= value_len
;
129 info
->bin_attr
.read
= vpd_attrib_read
;
130 info
->bin_attr
.private = info
;
134 INIT_LIST_HEAD(&info
->list
);
135 list_add_tail(&info
->list
, &sec
->attribs
);
137 ret
= sysfs_create_bin_file(sec
->kobj
, &info
->bin_attr
);
146 static void vpd_section_attrib_destroy(struct vpd_section
*sec
)
148 struct vpd_attrib_info
*info
;
149 struct vpd_attrib_info
*temp
;
151 list_for_each_entry_safe(info
, temp
, &sec
->attribs
, list
) {
153 sysfs_remove_bin_file(sec
->kobj
, &info
->bin_attr
);
158 static ssize_t
vpd_section_read(struct file
*filp
, struct kobject
*kobp
,
159 struct bin_attribute
*bin_attr
, char *buf
,
160 loff_t pos
, size_t count
)
162 struct vpd_section
*sec
= bin_attr
->private;
164 return memory_read_from_buffer(buf
, count
, &pos
, sec
->baseaddr
,
168 static int vpd_section_create_attribs(struct vpd_section
*sec
)
175 ret
= vpd_decode_string(sec
->bin_attr
.size
, sec
->baseaddr
,
176 &consumed
, vpd_section_attrib_add
, sec
);
177 } while (ret
== VPD_OK
);
182 static int vpd_section_init(const char *name
, struct vpd_section
*sec
,
183 phys_addr_t physaddr
, size_t size
)
188 sec
->baseaddr
= memremap(physaddr
, size
, MEMREMAP_WB
);
194 /* We want to export the raw partion with name ${name}_raw */
195 raw_len
= strlen(name
) + 5;
196 sec
->raw_name
= kzalloc(raw_len
, GFP_KERNEL
);
197 strncpy(sec
->raw_name
, name
, raw_len
);
198 strncat(sec
->raw_name
, "_raw", raw_len
);
200 sysfs_bin_attr_init(&sec
->bin_attr
);
201 sec
->bin_attr
.attr
.name
= sec
->raw_name
;
202 sec
->bin_attr
.attr
.mode
= 0444;
203 sec
->bin_attr
.size
= size
;
204 sec
->bin_attr
.read
= vpd_section_read
;
205 sec
->bin_attr
.private = sec
;
207 ret
= sysfs_create_bin_file(vpd_kobj
, &sec
->bin_attr
);
211 sec
->kobj
= kobject_create_and_add(name
, vpd_kobj
);
217 INIT_LIST_HEAD(&sec
->attribs
);
218 vpd_section_create_attribs(sec
);
225 sysfs_remove_bin_file(vpd_kobj
, &sec
->bin_attr
);
228 kfree(sec
->raw_name
);
229 iounmap(sec
->baseaddr
);
234 static int vpd_section_destroy(struct vpd_section
*sec
)
237 vpd_section_attrib_destroy(sec
);
238 kobject_del(sec
->kobj
);
239 sysfs_remove_bin_file(vpd_kobj
, &sec
->bin_attr
);
240 kfree(sec
->raw_name
);
241 iounmap(sec
->baseaddr
);
247 static int vpd_sections_init(phys_addr_t physaddr
)
249 struct vpd_cbmem __iomem
*temp
;
250 struct vpd_cbmem header
;
253 temp
= memremap(physaddr
, sizeof(struct vpd_cbmem
), MEMREMAP_WB
);
257 memcpy_fromio(&header
, temp
, sizeof(struct vpd_cbmem
));
260 if (header
.magic
!= VPD_CBMEM_MAGIC
)
263 if (header
.ro_size
) {
264 ret
= vpd_section_init("ro", &ro_vpd
,
265 physaddr
+ sizeof(struct vpd_cbmem
),
271 if (header
.rw_size
) {
272 ret
= vpd_section_init("rw", &rw_vpd
,
273 physaddr
+ sizeof(struct vpd_cbmem
) +
274 header
.ro_size
, header
.rw_size
);
282 static int vpd_probe(struct platform_device
*pdev
)
285 struct lb_cbmem_ref entry
;
287 ret
= coreboot_table_find(CB_TAG_VPD
, &entry
, sizeof(entry
));
291 return vpd_sections_init(entry
.cbmem_addr
);
294 static struct platform_driver vpd_driver
= {
301 static int __init
vpd_platform_init(void)
303 struct platform_device
*pdev
;
305 pdev
= platform_device_register_simple("vpd", -1, NULL
, 0);
307 return PTR_ERR(pdev
);
309 vpd_kobj
= kobject_create_and_add("vpd", firmware_kobj
);
313 memset(&ro_vpd
, 0, sizeof(ro_vpd
));
314 memset(&rw_vpd
, 0, sizeof(rw_vpd
));
316 platform_driver_register(&vpd_driver
);
321 static void __exit
vpd_platform_exit(void)
323 vpd_section_destroy(&ro_vpd
);
324 vpd_section_destroy(&rw_vpd
);
325 kobject_del(vpd_kobj
);
328 module_init(vpd_platform_init
);
329 module_exit(vpd_platform_exit
);
331 MODULE_AUTHOR("Google, Inc.");
332 MODULE_LICENSE("GPL");