0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/string.h>
0009 #include <linux/firmware-map.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/types.h>
0013 #include <linux/memblock.h>
0014 #include <linux/slab.h>
0015 #include <linux/mm.h>
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 struct firmware_map_entry {
0027
0028
0029
0030
0031 u64 start;
0032 u64 end;
0033 const char *type;
0034 struct list_head list;
0035 struct kobject kobj;
0036 };
0037
0038
0039
0040
0041 static ssize_t memmap_attr_show(struct kobject *kobj,
0042 struct attribute *attr, char *buf);
0043 static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
0044 static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
0045 static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
0046
0047 static struct firmware_map_entry * __meminit
0048 firmware_map_find_entry(u64 start, u64 end, const char *type);
0049
0050
0051
0052
0053
0054 struct memmap_attribute {
0055 struct attribute attr;
0056 ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
0057 };
0058
0059 static struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
0060 static struct memmap_attribute memmap_end_attr = __ATTR_RO(end);
0061 static struct memmap_attribute memmap_type_attr = __ATTR_RO(type);
0062
0063
0064
0065
0066 static struct attribute *def_attrs[] = {
0067 &memmap_start_attr.attr,
0068 &memmap_end_attr.attr,
0069 &memmap_type_attr.attr,
0070 NULL
0071 };
0072 ATTRIBUTE_GROUPS(def);
0073
0074 static const struct sysfs_ops memmap_attr_ops = {
0075 .show = memmap_attr_show,
0076 };
0077
0078
0079 static LIST_HEAD(map_entries);
0080 static DEFINE_SPINLOCK(map_entries_lock);
0081
0082
0083
0084
0085
0086
0087
0088 static LIST_HEAD(map_entries_bootmem);
0089 static DEFINE_SPINLOCK(map_entries_bootmem_lock);
0090
0091
0092 static inline struct firmware_map_entry *
0093 to_memmap_entry(struct kobject *kobj)
0094 {
0095 return container_of(kobj, struct firmware_map_entry, kobj);
0096 }
0097
0098 static void __meminit release_firmware_map_entry(struct kobject *kobj)
0099 {
0100 struct firmware_map_entry *entry = to_memmap_entry(kobj);
0101
0102 if (PageReserved(virt_to_page(entry))) {
0103
0104
0105
0106
0107
0108
0109 spin_lock(&map_entries_bootmem_lock);
0110 list_add(&entry->list, &map_entries_bootmem);
0111 spin_unlock(&map_entries_bootmem_lock);
0112
0113 return;
0114 }
0115
0116 kfree(entry);
0117 }
0118
0119 static struct kobj_type __refdata memmap_ktype = {
0120 .release = release_firmware_map_entry,
0121 .sysfs_ops = &memmap_attr_ops,
0122 .default_groups = def_groups,
0123 };
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142 static int firmware_map_add_entry(u64 start, u64 end,
0143 const char *type,
0144 struct firmware_map_entry *entry)
0145 {
0146 BUG_ON(start > end);
0147
0148 entry->start = start;
0149 entry->end = end - 1;
0150 entry->type = type;
0151 INIT_LIST_HEAD(&entry->list);
0152 kobject_init(&entry->kobj, &memmap_ktype);
0153
0154 spin_lock(&map_entries_lock);
0155 list_add_tail(&entry->list, &map_entries);
0156 spin_unlock(&map_entries_lock);
0157
0158 return 0;
0159 }
0160
0161
0162
0163
0164
0165
0166
0167
0168 static inline void firmware_map_remove_entry(struct firmware_map_entry *entry)
0169 {
0170 list_del(&entry->list);
0171 }
0172
0173
0174
0175
0176 static int add_sysfs_fw_map_entry(struct firmware_map_entry *entry)
0177 {
0178 static int map_entries_nr;
0179 static struct kset *mmap_kset;
0180
0181 if (entry->kobj.state_in_sysfs)
0182 return -EEXIST;
0183
0184 if (!mmap_kset) {
0185 mmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
0186 if (!mmap_kset)
0187 return -ENOMEM;
0188 }
0189
0190 entry->kobj.kset = mmap_kset;
0191 if (kobject_add(&entry->kobj, NULL, "%d", map_entries_nr++))
0192 kobject_put(&entry->kobj);
0193
0194 return 0;
0195 }
0196
0197
0198
0199
0200 static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry)
0201 {
0202 kobject_put(&entry->kobj);
0203 }
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 static struct firmware_map_entry * __meminit
0219 firmware_map_find_entry_in_list(u64 start, u64 end, const char *type,
0220 struct list_head *list)
0221 {
0222 struct firmware_map_entry *entry;
0223
0224 list_for_each_entry(entry, list, list)
0225 if ((entry->start == start) && (entry->end == end) &&
0226 (!strcmp(entry->type, type))) {
0227 return entry;
0228 }
0229
0230 return NULL;
0231 }
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 static struct firmware_map_entry * __meminit
0246 firmware_map_find_entry(u64 start, u64 end, const char *type)
0247 {
0248 return firmware_map_find_entry_in_list(start, end, type, &map_entries);
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 static struct firmware_map_entry * __meminit
0263 firmware_map_find_entry_bootmem(u64 start, u64 end, const char *type)
0264 {
0265 return firmware_map_find_entry_in_list(start, end, type,
0266 &map_entries_bootmem);
0267 }
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282 int __meminit firmware_map_add_hotplug(u64 start, u64 end, const char *type)
0283 {
0284 struct firmware_map_entry *entry;
0285
0286 entry = firmware_map_find_entry(start, end - 1, type);
0287 if (entry)
0288 return 0;
0289
0290 entry = firmware_map_find_entry_bootmem(start, end - 1, type);
0291 if (!entry) {
0292 entry = kzalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
0293 if (!entry)
0294 return -ENOMEM;
0295 } else {
0296
0297 spin_lock(&map_entries_bootmem_lock);
0298 list_del(&entry->list);
0299 spin_unlock(&map_entries_bootmem_lock);
0300
0301 memset(entry, 0, sizeof(*entry));
0302 }
0303
0304 firmware_map_add_entry(start, end, type, entry);
0305
0306 add_sysfs_fw_map_entry(entry);
0307
0308 return 0;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 int __init firmware_map_add_early(u64 start, u64 end, const char *type)
0325 {
0326 struct firmware_map_entry *entry;
0327
0328 entry = memblock_alloc(sizeof(struct firmware_map_entry),
0329 SMP_CACHE_BYTES);
0330 if (WARN_ON(!entry))
0331 return -ENOMEM;
0332
0333 return firmware_map_add_entry(start, end, type, entry);
0334 }
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 int __meminit firmware_map_remove(u64 start, u64 end, const char *type)
0347 {
0348 struct firmware_map_entry *entry;
0349
0350 spin_lock(&map_entries_lock);
0351 entry = firmware_map_find_entry(start, end - 1, type);
0352 if (!entry) {
0353 spin_unlock(&map_entries_lock);
0354 return -EINVAL;
0355 }
0356
0357 firmware_map_remove_entry(entry);
0358 spin_unlock(&map_entries_lock);
0359
0360
0361 remove_sysfs_fw_map_entry(entry);
0362
0363 return 0;
0364 }
0365
0366
0367
0368
0369
0370 static ssize_t start_show(struct firmware_map_entry *entry, char *buf)
0371 {
0372 return snprintf(buf, PAGE_SIZE, "0x%llx\n",
0373 (unsigned long long)entry->start);
0374 }
0375
0376 static ssize_t end_show(struct firmware_map_entry *entry, char *buf)
0377 {
0378 return snprintf(buf, PAGE_SIZE, "0x%llx\n",
0379 (unsigned long long)entry->end);
0380 }
0381
0382 static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
0383 {
0384 return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
0385 }
0386
0387 static inline struct memmap_attribute *to_memmap_attr(struct attribute *attr)
0388 {
0389 return container_of(attr, struct memmap_attribute, attr);
0390 }
0391
0392 static ssize_t memmap_attr_show(struct kobject *kobj,
0393 struct attribute *attr, char *buf)
0394 {
0395 struct firmware_map_entry *entry = to_memmap_entry(kobj);
0396 struct memmap_attribute *memmap_attr = to_memmap_attr(attr);
0397
0398 return memmap_attr->show(entry, buf);
0399 }
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 static int __init firmware_memmap_init(void)
0410 {
0411 struct firmware_map_entry *entry;
0412
0413 list_for_each_entry(entry, &map_entries, list)
0414 add_sysfs_fw_map_entry(entry);
0415
0416 return 0;
0417 }
0418 late_initcall(firmware_memmap_init);
0419