selinux: kill 'flags' argument in avc_has_perm_flags() and avc_audit()
[sfrench/cifs-2.6.git] / drivers / platform / x86 / intel_speed_select_if / isst_if_common.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Intel Speed Select Interface: Common functions
4  * Copyright (c) 2019, Intel Corporation.
5  * All rights reserved.
6  *
7  * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
8  */
9
10 #include <linux/cpufeature.h>
11 #include <linux/cpuhotplug.h>
12 #include <linux/fs.h>
13 #include <linux/hashtable.h>
14 #include <linux/miscdevice.h>
15 #include <linux/module.h>
16 #include <linux/pci.h>
17 #include <linux/sched/signal.h>
18 #include <linux/slab.h>
19 #include <linux/uaccess.h>
20 #include <uapi/linux/isst_if.h>
21
22 #include "isst_if_common.h"
23
24 #define MSR_THREAD_ID_INFO      0x53
25 #define MSR_CPU_BUS_NUMBER      0x128
26
27 static struct isst_if_cmd_cb punit_callbacks[ISST_IF_DEV_MAX];
28
29 static int punit_msr_white_list[] = {
30         MSR_TURBO_RATIO_LIMIT,
31         MSR_CONFIG_TDP_CONTROL,
32         MSR_TURBO_RATIO_LIMIT1,
33         MSR_TURBO_RATIO_LIMIT2,
34 };
35
36 struct isst_valid_cmd_ranges {
37         u16 cmd;
38         u16 sub_cmd_beg;
39         u16 sub_cmd_end;
40 };
41
42 struct isst_cmd_set_req_type {
43         u16 cmd;
44         u16 sub_cmd;
45         u16 param;
46 };
47
48 static const struct isst_valid_cmd_ranges isst_valid_cmds[] = {
49         {0xD0, 0x00, 0x03},
50         {0x7F, 0x00, 0x0B},
51         {0x7F, 0x10, 0x12},
52         {0x7F, 0x20, 0x23},
53         {0x94, 0x03, 0x03},
54         {0x95, 0x03, 0x03},
55 };
56
57 static const struct isst_cmd_set_req_type isst_cmd_set_reqs[] = {
58         {0xD0, 0x00, 0x08},
59         {0xD0, 0x01, 0x08},
60         {0xD0, 0x02, 0x08},
61         {0xD0, 0x03, 0x08},
62         {0x7F, 0x02, 0x00},
63         {0x7F, 0x08, 0x00},
64         {0x95, 0x03, 0x03},
65 };
66
67 struct isst_cmd {
68         struct hlist_node hnode;
69         u64 data;
70         u32 cmd;
71         int cpu;
72         int mbox_cmd_type;
73         u32 param;
74 };
75
76 static DECLARE_HASHTABLE(isst_hash, 8);
77 static DEFINE_MUTEX(isst_hash_lock);
78
79 static int isst_store_new_cmd(int cmd, u32 cpu, int mbox_cmd_type, u32 param,
80                               u32 data)
81 {
82         struct isst_cmd *sst_cmd;
83
84         sst_cmd = kmalloc(sizeof(*sst_cmd), GFP_KERNEL);
85         if (!sst_cmd)
86                 return -ENOMEM;
87
88         sst_cmd->cpu = cpu;
89         sst_cmd->cmd = cmd;
90         sst_cmd->mbox_cmd_type = mbox_cmd_type;
91         sst_cmd->param = param;
92         sst_cmd->data = data;
93
94         hash_add(isst_hash, &sst_cmd->hnode, sst_cmd->cmd);
95
96         return 0;
97 }
98
99 static void isst_delete_hash(void)
100 {
101         struct isst_cmd *sst_cmd;
102         struct hlist_node *tmp;
103         int i;
104
105         hash_for_each_safe(isst_hash, i, tmp, sst_cmd, hnode) {
106                 hash_del(&sst_cmd->hnode);
107                 kfree(sst_cmd);
108         }
109 }
110
111 /**
112  * isst_store_cmd() - Store command to a hash table
113  * @cmd: Mailbox command.
114  * @sub_cmd: Mailbox sub-command or MSR id.
115  * @mbox_cmd_type: Mailbox or MSR command.
116  * @param: Mailbox parameter.
117  * @data: Mailbox request data or MSR data.
118  *
119  * Stores the command to a hash table if there is no such command already
120  * stored. If already stored update the latest parameter and data for the
121  * command.
122  *
123  * Return: Return result of store to hash table, 0 for success, others for
124  * failure.
125  */
126 int isst_store_cmd(int cmd, int sub_cmd, u32 cpu, int mbox_cmd_type,
127                    u32 param, u64 data)
128 {
129         struct isst_cmd *sst_cmd;
130         int full_cmd, ret;
131
132         full_cmd = (cmd & GENMASK_ULL(15, 0)) << 16;
133         full_cmd |= (sub_cmd & GENMASK_ULL(15, 0));
134         mutex_lock(&isst_hash_lock);
135         hash_for_each_possible(isst_hash, sst_cmd, hnode, full_cmd) {
136                 if (sst_cmd->cmd == full_cmd && sst_cmd->cpu == cpu &&
137                     sst_cmd->mbox_cmd_type == mbox_cmd_type) {
138                         sst_cmd->param = param;
139                         sst_cmd->data = data;
140                         mutex_unlock(&isst_hash_lock);
141                         return 0;
142                 }
143         }
144
145         ret = isst_store_new_cmd(full_cmd, cpu, mbox_cmd_type, param, data);
146         mutex_unlock(&isst_hash_lock);
147
148         return ret;
149 }
150 EXPORT_SYMBOL_GPL(isst_store_cmd);
151
152 static void isst_mbox_resume_command(struct isst_if_cmd_cb *cb,
153                                      struct isst_cmd *sst_cmd)
154 {
155         struct isst_if_mbox_cmd mbox_cmd;
156         int wr_only;
157
158         mbox_cmd.command = (sst_cmd->cmd & GENMASK_ULL(31, 16)) >> 16;
159         mbox_cmd.sub_command = sst_cmd->cmd & GENMASK_ULL(15, 0);
160         mbox_cmd.parameter = sst_cmd->param;
161         mbox_cmd.req_data = sst_cmd->data;
162         mbox_cmd.logical_cpu = sst_cmd->cpu;
163         (cb->cmd_callback)((u8 *)&mbox_cmd, &wr_only, 1);
164 }
165
166 /**
167  * isst_resume_common() - Process Resume request
168  *
169  * On resume replay all mailbox commands and MSRs.
170  *
171  * Return: None.
172  */
173 void isst_resume_common(void)
174 {
175         struct isst_cmd *sst_cmd;
176         int i;
177
178         hash_for_each(isst_hash, i, sst_cmd, hnode) {
179                 struct isst_if_cmd_cb *cb;
180
181                 if (sst_cmd->mbox_cmd_type) {
182                         cb = &punit_callbacks[ISST_IF_DEV_MBOX];
183                         if (cb->registered)
184                                 isst_mbox_resume_command(cb, sst_cmd);
185                 } else {
186                         wrmsrl_safe_on_cpu(sst_cmd->cpu, sst_cmd->cmd,
187                                            sst_cmd->data);
188                 }
189         }
190 }
191 EXPORT_SYMBOL_GPL(isst_resume_common);
192
193 static void isst_restore_msr_local(int cpu)
194 {
195         struct isst_cmd *sst_cmd;
196         int i;
197
198         mutex_lock(&isst_hash_lock);
199         for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) {
200                 if (!punit_msr_white_list[i])
201                         break;
202
203                 hash_for_each_possible(isst_hash, sst_cmd, hnode,
204                                        punit_msr_white_list[i]) {
205                         if (!sst_cmd->mbox_cmd_type && sst_cmd->cpu == cpu)
206                                 wrmsrl_safe(sst_cmd->cmd, sst_cmd->data);
207                 }
208         }
209         mutex_unlock(&isst_hash_lock);
210 }
211
212 /**
213  * isst_if_mbox_cmd_invalid() - Check invalid mailbox commands
214  * @cmd: Pointer to the command structure to verify.
215  *
216  * Invalid command to PUNIT to may result in instability of the platform.
217  * This function has a whitelist of commands, which are allowed.
218  *
219  * Return: Return true if the command is invalid, else false.
220  */
221 bool isst_if_mbox_cmd_invalid(struct isst_if_mbox_cmd *cmd)
222 {
223         int i;
224
225         if (cmd->logical_cpu >= nr_cpu_ids)
226                 return true;
227
228         for (i = 0; i < ARRAY_SIZE(isst_valid_cmds); ++i) {
229                 if (cmd->command == isst_valid_cmds[i].cmd &&
230                     (cmd->sub_command >= isst_valid_cmds[i].sub_cmd_beg &&
231                      cmd->sub_command <= isst_valid_cmds[i].sub_cmd_end)) {
232                         return false;
233                 }
234         }
235
236         return true;
237 }
238 EXPORT_SYMBOL_GPL(isst_if_mbox_cmd_invalid);
239
240 /**
241  * isst_if_mbox_cmd_set_req() - Check mailbox command is a set request
242  * @cmd: Pointer to the command structure to verify.
243  *
244  * Check if the given mail box level is set request and not a get request.
245  *
246  * Return: Return true if the command is set_req, else false.
247  */
248 bool isst_if_mbox_cmd_set_req(struct isst_if_mbox_cmd *cmd)
249 {
250         int i;
251
252         for (i = 0; i < ARRAY_SIZE(isst_cmd_set_reqs); ++i) {
253                 if (cmd->command == isst_cmd_set_reqs[i].cmd &&
254                     cmd->sub_command == isst_cmd_set_reqs[i].sub_cmd &&
255                     cmd->parameter == isst_cmd_set_reqs[i].param) {
256                         return true;
257                 }
258         }
259
260         return false;
261 }
262 EXPORT_SYMBOL_GPL(isst_if_mbox_cmd_set_req);
263
264 static int isst_if_get_platform_info(void __user *argp)
265 {
266         struct isst_if_platform_info info;
267
268         info.api_version = ISST_IF_API_VERSION,
269         info.driver_version = ISST_IF_DRIVER_VERSION,
270         info.max_cmds_per_ioctl = ISST_IF_CMD_LIMIT,
271         info.mbox_supported = punit_callbacks[ISST_IF_DEV_MBOX].registered;
272         info.mmio_supported = punit_callbacks[ISST_IF_DEV_MMIO].registered;
273
274         if (copy_to_user(argp, &info, sizeof(info)))
275                 return -EFAULT;
276
277         return 0;
278 }
279
280
281 struct isst_if_cpu_info {
282         /* For BUS 0 and BUS 1 only, which we need for PUNIT interface */
283         int bus_info[2];
284         int punit_cpu_id;
285 };
286
287 static struct isst_if_cpu_info *isst_cpu_info;
288
289 /**
290  * isst_if_get_pci_dev() - Get the PCI device instance for a CPU
291  * @cpu: Logical CPU number.
292  * @bus_number: The bus number assigned by the hardware.
293  * @dev: The device number assigned by the hardware.
294  * @fn: The function number assigned by the hardware.
295  *
296  * Using cached bus information, find out the PCI device for a bus number,
297  * device and function.
298  *
299  * Return: Return pci_dev pointer or NULL.
300  */
301 struct pci_dev *isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn)
302 {
303         int bus_number;
304
305         if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids ||
306             cpu >= num_possible_cpus())
307                 return NULL;
308
309         bus_number = isst_cpu_info[cpu].bus_info[bus_no];
310         if (bus_number < 0)
311                 return NULL;
312
313         return pci_get_domain_bus_and_slot(0, bus_number, PCI_DEVFN(dev, fn));
314 }
315 EXPORT_SYMBOL_GPL(isst_if_get_pci_dev);
316
317 static int isst_if_cpu_online(unsigned int cpu)
318 {
319         u64 data;
320         int ret;
321
322         ret = rdmsrl_safe(MSR_CPU_BUS_NUMBER, &data);
323         if (ret) {
324                 /* This is not a fatal error on MSR mailbox only I/F */
325                 isst_cpu_info[cpu].bus_info[0] = -1;
326                 isst_cpu_info[cpu].bus_info[1] = -1;
327         } else {
328                 isst_cpu_info[cpu].bus_info[0] = data & 0xff;
329                 isst_cpu_info[cpu].bus_info[1] = (data >> 8) & 0xff;
330         }
331
332         ret = rdmsrl_safe(MSR_THREAD_ID_INFO, &data);
333         if (ret) {
334                 isst_cpu_info[cpu].punit_cpu_id = -1;
335                 return ret;
336         }
337         isst_cpu_info[cpu].punit_cpu_id = data;
338
339         isst_restore_msr_local(cpu);
340
341         return 0;
342 }
343
344 static int isst_if_online_id;
345
346 static int isst_if_cpu_info_init(void)
347 {
348         int ret;
349
350         isst_cpu_info = kcalloc(num_possible_cpus(),
351                                 sizeof(*isst_cpu_info),
352                                 GFP_KERNEL);
353         if (!isst_cpu_info)
354                 return -ENOMEM;
355
356         ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
357                                 "platform/x86/isst-if:online",
358                                 isst_if_cpu_online, NULL);
359         if (ret < 0) {
360                 kfree(isst_cpu_info);
361                 return ret;
362         }
363
364         isst_if_online_id = ret;
365
366         return 0;
367 }
368
369 static void isst_if_cpu_info_exit(void)
370 {
371         cpuhp_remove_state(isst_if_online_id);
372         kfree(isst_cpu_info);
373 };
374
375 static long isst_if_proc_phyid_req(u8 *cmd_ptr, int *write_only, int resume)
376 {
377         struct isst_if_cpu_map *cpu_map;
378
379         cpu_map = (struct isst_if_cpu_map *)cmd_ptr;
380         if (cpu_map->logical_cpu >= nr_cpu_ids ||
381             cpu_map->logical_cpu >= num_possible_cpus())
382                 return -EINVAL;
383
384         *write_only = 0;
385         cpu_map->physical_cpu = isst_cpu_info[cpu_map->logical_cpu].punit_cpu_id;
386
387         return 0;
388 }
389
390 static bool match_punit_msr_white_list(int msr)
391 {
392         int i;
393
394         for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) {
395                 if (punit_msr_white_list[i] == msr)
396                         return true;
397         }
398
399         return false;
400 }
401
402 static long isst_if_msr_cmd_req(u8 *cmd_ptr, int *write_only, int resume)
403 {
404         struct isst_if_msr_cmd *msr_cmd;
405         int ret;
406
407         msr_cmd = (struct isst_if_msr_cmd *)cmd_ptr;
408
409         if (!match_punit_msr_white_list(msr_cmd->msr))
410                 return -EINVAL;
411
412         if (msr_cmd->logical_cpu >= nr_cpu_ids)
413                 return -EINVAL;
414
415         if (msr_cmd->read_write) {
416                 if (!capable(CAP_SYS_ADMIN))
417                         return -EPERM;
418
419                 ret = wrmsrl_safe_on_cpu(msr_cmd->logical_cpu,
420                                          msr_cmd->msr,
421                                          msr_cmd->data);
422                 *write_only = 1;
423                 if (!ret && !resume)
424                         ret = isst_store_cmd(0, msr_cmd->msr,
425                                              msr_cmd->logical_cpu,
426                                              0, 0, msr_cmd->data);
427         } else {
428                 u64 data;
429
430                 ret = rdmsrl_safe_on_cpu(msr_cmd->logical_cpu,
431                                          msr_cmd->msr, &data);
432                 if (!ret) {
433                         msr_cmd->data = data;
434                         *write_only = 0;
435                 }
436         }
437
438
439         return ret;
440 }
441
442 static long isst_if_exec_multi_cmd(void __user *argp, struct isst_if_cmd_cb *cb)
443 {
444         unsigned char __user *ptr;
445         u32 cmd_count;
446         u8 *cmd_ptr;
447         long ret;
448         int i;
449
450         /* Each multi command has u32 command count as the first field */
451         if (copy_from_user(&cmd_count, argp, sizeof(cmd_count)))
452                 return -EFAULT;
453
454         if (!cmd_count || cmd_count > ISST_IF_CMD_LIMIT)
455                 return -EINVAL;
456
457         cmd_ptr = kmalloc(cb->cmd_size, GFP_KERNEL);
458         if (!cmd_ptr)
459                 return -ENOMEM;
460
461         /* cb->offset points to start of the command after the command count */
462         ptr = argp + cb->offset;
463
464         for (i = 0; i < cmd_count; ++i) {
465                 int wr_only;
466
467                 if (signal_pending(current)) {
468                         ret = -EINTR;
469                         break;
470                 }
471
472                 if (copy_from_user(cmd_ptr, ptr, cb->cmd_size)) {
473                         ret = -EFAULT;
474                         break;
475                 }
476
477                 ret = cb->cmd_callback(cmd_ptr, &wr_only, 0);
478                 if (ret)
479                         break;
480
481                 if (!wr_only && copy_to_user(ptr, cmd_ptr, cb->cmd_size)) {
482                         ret = -EFAULT;
483                         break;
484                 }
485
486                 ptr += cb->cmd_size;
487         }
488
489         kfree(cmd_ptr);
490
491         return i ? i : ret;
492 }
493
494 static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
495                               unsigned long arg)
496 {
497         void __user *argp = (void __user *)arg;
498         struct isst_if_cmd_cb cmd_cb;
499         struct isst_if_cmd_cb *cb;
500         long ret = -ENOTTY;
501
502         switch (cmd) {
503         case ISST_IF_GET_PLATFORM_INFO:
504                 ret = isst_if_get_platform_info(argp);
505                 break;
506         case ISST_IF_GET_PHY_ID:
507                 cmd_cb.cmd_size = sizeof(struct isst_if_cpu_map);
508                 cmd_cb.offset = offsetof(struct isst_if_cpu_maps, cpu_map);
509                 cmd_cb.cmd_callback = isst_if_proc_phyid_req;
510                 ret = isst_if_exec_multi_cmd(argp, &cmd_cb);
511                 break;
512         case ISST_IF_IO_CMD:
513                 cb = &punit_callbacks[ISST_IF_DEV_MMIO];
514                 if (cb->registered)
515                         ret = isst_if_exec_multi_cmd(argp, cb);
516                 break;
517         case ISST_IF_MBOX_COMMAND:
518                 cb = &punit_callbacks[ISST_IF_DEV_MBOX];
519                 if (cb->registered)
520                         ret = isst_if_exec_multi_cmd(argp, cb);
521                 break;
522         case ISST_IF_MSR_COMMAND:
523                 cmd_cb.cmd_size = sizeof(struct isst_if_msr_cmd);
524                 cmd_cb.offset = offsetof(struct isst_if_msr_cmds, msr_cmd);
525                 cmd_cb.cmd_callback = isst_if_msr_cmd_req;
526                 ret = isst_if_exec_multi_cmd(argp, &cmd_cb);
527                 break;
528         default:
529                 break;
530         }
531
532         return ret;
533 }
534
535 static DEFINE_MUTEX(punit_misc_dev_lock);
536 static int misc_usage_count;
537 static int misc_device_ret;
538 static int misc_device_open;
539
540 static int isst_if_open(struct inode *inode, struct file *file)
541 {
542         int i, ret = 0;
543
544         /* Fail open, if a module is going away */
545         mutex_lock(&punit_misc_dev_lock);
546         for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
547                 struct isst_if_cmd_cb *cb = &punit_callbacks[i];
548
549                 if (cb->registered && !try_module_get(cb->owner)) {
550                         ret = -ENODEV;
551                         break;
552                 }
553         }
554         if (ret) {
555                 int j;
556
557                 for (j = 0; j < i; ++j) {
558                         struct isst_if_cmd_cb *cb;
559
560                         cb = &punit_callbacks[j];
561                         if (cb->registered)
562                                 module_put(cb->owner);
563                 }
564         } else {
565                 misc_device_open++;
566         }
567         mutex_unlock(&punit_misc_dev_lock);
568
569         return ret;
570 }
571
572 static int isst_if_relase(struct inode *inode, struct file *f)
573 {
574         int i;
575
576         mutex_lock(&punit_misc_dev_lock);
577         misc_device_open--;
578         for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
579                 struct isst_if_cmd_cb *cb = &punit_callbacks[i];
580
581                 if (cb->registered)
582                         module_put(cb->owner);
583         }
584         mutex_unlock(&punit_misc_dev_lock);
585
586         return 0;
587 }
588
589 static const struct file_operations isst_if_char_driver_ops = {
590         .open = isst_if_open,
591         .unlocked_ioctl = isst_if_def_ioctl,
592         .release = isst_if_relase,
593 };
594
595 static struct miscdevice isst_if_char_driver = {
596         .minor          = MISC_DYNAMIC_MINOR,
597         .name           = "isst_interface",
598         .fops           = &isst_if_char_driver_ops,
599 };
600
601 /**
602  * isst_if_cdev_register() - Register callback for IOCTL
603  * @device_type: The device type this callback handling.
604  * @cb: Callback structure.
605  *
606  * This function registers a callback to device type. On very first call
607  * it will register a misc device, which is used for user kernel interface.
608  * Other calls simply increment ref count. Registry will fail, if the user
609  * already opened misc device for operation. Also if the misc device
610  * creation failed, then it will not try again and all callers will get
611  * failure code.
612  *
613  * Return: Return the return value from the misc creation device or -EINVAL
614  * for unsupported device type.
615  */
616 int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
617 {
618         if (misc_device_ret)
619                 return misc_device_ret;
620
621         if (device_type >= ISST_IF_DEV_MAX)
622                 return -EINVAL;
623
624         mutex_lock(&punit_misc_dev_lock);
625         if (misc_device_open) {
626                 mutex_unlock(&punit_misc_dev_lock);
627                 return -EAGAIN;
628         }
629         if (!misc_usage_count) {
630                 int ret;
631
632                 misc_device_ret = misc_register(&isst_if_char_driver);
633                 if (misc_device_ret)
634                         goto unlock_exit;
635
636                 ret = isst_if_cpu_info_init();
637                 if (ret) {
638                         misc_deregister(&isst_if_char_driver);
639                         misc_device_ret = ret;
640                         goto unlock_exit;
641                 }
642         }
643         memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
644         punit_callbacks[device_type].registered = 1;
645         misc_usage_count++;
646 unlock_exit:
647         mutex_unlock(&punit_misc_dev_lock);
648
649         return misc_device_ret;
650 }
651 EXPORT_SYMBOL_GPL(isst_if_cdev_register);
652
653 /**
654  * isst_if_cdev_unregister() - Unregister callback for IOCTL
655  * @device_type: The device type to unregister.
656  *
657  * This function unregisters the previously registered callback. If this
658  * is the last callback unregistering, then misc device is removed.
659  *
660  * Return: None.
661  */
662 void isst_if_cdev_unregister(int device_type)
663 {
664         mutex_lock(&punit_misc_dev_lock);
665         misc_usage_count--;
666         punit_callbacks[device_type].registered = 0;
667         if (device_type == ISST_IF_DEV_MBOX)
668                 isst_delete_hash();
669         if (!misc_usage_count && !misc_device_ret) {
670                 misc_deregister(&isst_if_char_driver);
671                 isst_if_cpu_info_exit();
672         }
673         mutex_unlock(&punit_misc_dev_lock);
674 }
675 EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
676
677 MODULE_LICENSE("GPL v2");