forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/misc/mei/main.c
....@@ -1,18 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
2
- *
3
+ * Copyright (c) 2003-2020, Intel Corporation. All rights reserved.
34 * Intel Management Engine Interface (Intel MEI) Linux driver
4
- * Copyright (c) 2003-2018, Intel Corporation.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms and conditions of the GNU General Public License,
8
- * version 2, as published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope it will be useful, but WITHOUT
11
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
- * more details.
14
- *
155 */
6
+
167 #include <linux/module.h>
178 #include <linux/moduleparam.h>
189 #include <linux/kernel.h>
....@@ -36,6 +27,12 @@
3627
3728 #include "mei_dev.h"
3829 #include "client.h"
30
+
31
+static struct class *mei_class;
32
+static dev_t mei_devt;
33
+#define MEI_MAX_DEVS MINORMASK
34
+static DEFINE_MUTEX(mei_minor_lock);
35
+static DEFINE_IDR(mei_idr);
3936
4037 /**
4138 * mei_open - the open function
....@@ -84,6 +81,27 @@
8481 }
8582
8683 /**
84
+ * mei_cl_vtag_remove_by_fp - remove vtag that corresponds to fp from list
85
+ *
86
+ * @cl: host client
87
+ * @fp: pointer to file structure
88
+ *
89
+ */
90
+static void mei_cl_vtag_remove_by_fp(const struct mei_cl *cl,
91
+ const struct file *fp)
92
+{
93
+ struct mei_cl_vtag *vtag_l, *next;
94
+
95
+ list_for_each_entry_safe(vtag_l, next, &cl->vtag_map, list) {
96
+ if (vtag_l->fp == fp) {
97
+ list_del(&vtag_l->list);
98
+ kfree(vtag_l);
99
+ return;
100
+ }
101
+ }
102
+}
103
+
104
+/**
87105 * mei_release - the release function
88106 *
89107 * @inode: pointer to inode structure
....@@ -104,16 +122,34 @@
104122
105123 mutex_lock(&dev->device_lock);
106124
107
- rets = mei_cl_disconnect(cl);
125
+ mei_cl_vtag_remove_by_fp(cl, file);
108126
109
- mei_cl_flush_queues(cl, file);
127
+ if (!list_empty(&cl->vtag_map)) {
128
+ cl_dbg(dev, cl, "not the last vtag\n");
129
+ mei_cl_flush_queues(cl, file);
130
+ rets = 0;
131
+ goto out;
132
+ }
133
+
134
+ rets = mei_cl_disconnect(cl);
135
+ /*
136
+ * Check again: This is necessary since disconnect releases the lock
137
+ * and another client can connect in the meantime.
138
+ */
139
+ if (!list_empty(&cl->vtag_map)) {
140
+ cl_dbg(dev, cl, "not the last vtag after disconnect\n");
141
+ mei_cl_flush_queues(cl, file);
142
+ goto out;
143
+ }
144
+
145
+ mei_cl_flush_queues(cl, NULL);
110146 cl_dbg(dev, cl, "removing\n");
111147
112148 mei_cl_unlink(cl);
113
-
114
- file->private_data = NULL;
115
-
116149 kfree(cl);
150
+
151
+out:
152
+ file->private_data = NULL;
117153
118154 mutex_unlock(&dev->device_lock);
119155 return rets;
....@@ -181,7 +217,7 @@
181217
182218 mutex_unlock(&dev->device_lock);
183219 if (wait_event_interruptible(cl->rx_wait,
184
- !list_empty(&cl->rd_completed) ||
220
+ mei_cl_read_cb(cl, file) ||
185221 !mei_cl_is_connected(cl))) {
186222 if (signal_pending(current))
187223 return -EINTR;
....@@ -232,7 +268,7 @@
232268 goto out;
233269
234270 free:
235
- mei_io_cb_free(cb);
271
+ mei_cl_del_rd_completed(cl, cb);
236272 *offset = 0;
237273
238274 out:
....@@ -240,6 +276,28 @@
240276 mutex_unlock(&dev->device_lock);
241277 return rets;
242278 }
279
+
280
+/**
281
+ * mei_cl_vtag_by_fp - obtain the vtag by file pointer
282
+ *
283
+ * @cl: host client
284
+ * @fp: pointer to file structure
285
+ *
286
+ * Return: vtag value on success, otherwise 0
287
+ */
288
+static u8 mei_cl_vtag_by_fp(const struct mei_cl *cl, const struct file *fp)
289
+{
290
+ struct mei_cl_vtag *cl_vtag;
291
+
292
+ if (!fp)
293
+ return 0;
294
+
295
+ list_for_each_entry(cl_vtag, &cl->vtag_map, list)
296
+ if (cl_vtag->fp == fp)
297
+ return cl_vtag->vtag;
298
+ return 0;
299
+}
300
+
243301 /**
244302 * mei_write - the write function.
245303 *
....@@ -317,6 +375,7 @@
317375 rets = -ENOMEM;
318376 goto out;
319377 }
378
+ cb->vtag = mei_cl_vtag_by_fp(cl, file);
320379
321380 rets = copy_from_user(cb->buf.data, ubuf, length);
322381 if (rets) {
....@@ -336,17 +395,18 @@
336395 * mei_ioctl_connect_client - the connect to fw client IOCTL function
337396 *
338397 * @file: private data of the file object
339
- * @data: IOCTL connect data, input and output parameters
398
+ * @in_client_uuid: requested UUID for connection
399
+ * @client: IOCTL connect data, output parameters
340400 *
341401 * Locking: called under "dev->device_lock" lock
342402 *
343403 * Return: 0 on success, <0 on failure.
344404 */
345405 static int mei_ioctl_connect_client(struct file *file,
346
- struct mei_connect_client_data *data)
406
+ const uuid_le *in_client_uuid,
407
+ struct mei_client *client)
347408 {
348409 struct mei_device *dev;
349
- struct mei_client *client;
350410 struct mei_me_client *me_cl;
351411 struct mei_cl *cl;
352412 int rets;
....@@ -354,18 +414,15 @@
354414 cl = file->private_data;
355415 dev = cl->dev;
356416
357
- if (dev->dev_state != MEI_DEV_ENABLED)
358
- return -ENODEV;
359
-
360417 if (cl->state != MEI_FILE_INITIALIZING &&
361418 cl->state != MEI_FILE_DISCONNECTED)
362419 return -EBUSY;
363420
364421 /* find ME client we're trying to connect to */
365
- me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
422
+ me_cl = mei_me_cl_by_uuid(dev, in_client_uuid);
366423 if (!me_cl) {
367424 dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
368
- &data->in_client_uuid);
425
+ in_client_uuid);
369426 rets = -ENOTTY;
370427 goto end;
371428 }
....@@ -375,7 +432,7 @@
375432 !dev->allow_fixed_address : !dev->hbm_f_fa_supported;
376433 if (forbidden) {
377434 dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
378
- &data->in_client_uuid);
435
+ in_client_uuid);
379436 rets = -ENOTTY;
380437 goto end;
381438 }
....@@ -389,7 +446,6 @@
389446 me_cl->props.max_msg_length);
390447
391448 /* prepare the output buffer */
392
- client = &data->out_client_properties;
393449 client->max_msg_length = me_cl->props.max_msg_length;
394450 client->protocol_version = me_cl->props.protocol_version;
395451 dev_dbg(dev->dev, "Can connect?\n");
....@@ -399,6 +455,135 @@
399455 end:
400456 mei_me_cl_put(me_cl);
401457 return rets;
458
+}
459
+
460
+/**
461
+ * mei_vt_support_check - check if client support vtags
462
+ *
463
+ * Locking: called under "dev->device_lock" lock
464
+ *
465
+ * @dev: mei_device
466
+ * @uuid: client UUID
467
+ *
468
+ * Return:
469
+ * 0 - supported
470
+ * -ENOTTY - no such client
471
+ * -EOPNOTSUPP - vtags are not supported by client
472
+ */
473
+static int mei_vt_support_check(struct mei_device *dev, const uuid_le *uuid)
474
+{
475
+ struct mei_me_client *me_cl;
476
+ int ret;
477
+
478
+ if (!dev->hbm_f_vt_supported)
479
+ return -EOPNOTSUPP;
480
+
481
+ me_cl = mei_me_cl_by_uuid(dev, uuid);
482
+ if (!me_cl) {
483
+ dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
484
+ uuid);
485
+ return -ENOTTY;
486
+ }
487
+ ret = me_cl->props.vt_supported ? 0 : -EOPNOTSUPP;
488
+ mei_me_cl_put(me_cl);
489
+
490
+ return ret;
491
+}
492
+
493
+/**
494
+ * mei_ioctl_connect_vtag - connect to fw client with vtag IOCTL function
495
+ *
496
+ * @file: private data of the file object
497
+ * @in_client_uuid: requested UUID for connection
498
+ * @client: IOCTL connect data, output parameters
499
+ * @vtag: vm tag
500
+ *
501
+ * Locking: called under "dev->device_lock" lock
502
+ *
503
+ * Return: 0 on success, <0 on failure.
504
+ */
505
+static int mei_ioctl_connect_vtag(struct file *file,
506
+ const uuid_le *in_client_uuid,
507
+ struct mei_client *client,
508
+ u8 vtag)
509
+{
510
+ struct mei_device *dev;
511
+ struct mei_cl *cl;
512
+ struct mei_cl *pos;
513
+ struct mei_cl_vtag *cl_vtag;
514
+
515
+ cl = file->private_data;
516
+ dev = cl->dev;
517
+
518
+ dev_dbg(dev->dev, "FW Client %pUl vtag %d\n", in_client_uuid, vtag);
519
+
520
+ switch (cl->state) {
521
+ case MEI_FILE_DISCONNECTED:
522
+ if (mei_cl_vtag_by_fp(cl, file) != vtag) {
523
+ dev_err(dev->dev, "reconnect with different vtag\n");
524
+ return -EINVAL;
525
+ }
526
+ break;
527
+ case MEI_FILE_INITIALIZING:
528
+ /* malicious connect from another thread may push vtag */
529
+ if (!IS_ERR(mei_cl_fp_by_vtag(cl, vtag))) {
530
+ dev_err(dev->dev, "vtag already filled\n");
531
+ return -EINVAL;
532
+ }
533
+
534
+ list_for_each_entry(pos, &dev->file_list, link) {
535
+ if (pos == cl)
536
+ continue;
537
+ if (!pos->me_cl)
538
+ continue;
539
+
540
+ /* only search for same UUID */
541
+ if (uuid_le_cmp(*mei_cl_uuid(pos), *in_client_uuid))
542
+ continue;
543
+
544
+ /* if tag already exist try another fp */
545
+ if (!IS_ERR(mei_cl_fp_by_vtag(pos, vtag)))
546
+ continue;
547
+
548
+ /* replace cl with acquired one */
549
+ dev_dbg(dev->dev, "replacing with existing cl\n");
550
+ mei_cl_unlink(cl);
551
+ kfree(cl);
552
+ file->private_data = pos;
553
+ cl = pos;
554
+ break;
555
+ }
556
+
557
+ cl_vtag = mei_cl_vtag_alloc(file, vtag);
558
+ if (IS_ERR(cl_vtag))
559
+ return -ENOMEM;
560
+
561
+ list_add_tail(&cl_vtag->list, &cl->vtag_map);
562
+ break;
563
+ default:
564
+ return -EBUSY;
565
+ }
566
+
567
+ while (cl->state != MEI_FILE_INITIALIZING &&
568
+ cl->state != MEI_FILE_DISCONNECTED &&
569
+ cl->state != MEI_FILE_CONNECTED) {
570
+ mutex_unlock(&dev->device_lock);
571
+ wait_event_timeout(cl->wait,
572
+ (cl->state == MEI_FILE_CONNECTED ||
573
+ cl->state == MEI_FILE_DISCONNECTED ||
574
+ cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
575
+ cl->state == MEI_FILE_DISCONNECT_REPLY),
576
+ mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
577
+ mutex_lock(&dev->device_lock);
578
+ }
579
+
580
+ if (!mei_cl_is_connected(cl))
581
+ return mei_ioctl_connect_client(file, in_client_uuid, client);
582
+
583
+ client->max_msg_length = cl->me_cl->props.max_msg_length;
584
+ client->protocol_version = cl->me_cl->props.protocol_version;
585
+
586
+ return 0;
402587 }
403588
404589 /**
....@@ -457,7 +642,11 @@
457642 {
458643 struct mei_device *dev;
459644 struct mei_cl *cl = file->private_data;
460
- struct mei_connect_client_data connect_data;
645
+ struct mei_connect_client_data conn;
646
+ struct mei_connect_client_data_vtag conn_vtag;
647
+ const uuid_le *cl_uuid;
648
+ struct mei_client *props;
649
+ u8 vtag;
461650 u32 notify_get, notify_req;
462651 int rets;
463652
....@@ -478,20 +667,68 @@
478667 switch (cmd) {
479668 case IOCTL_MEI_CONNECT_CLIENT:
480669 dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
481
- if (copy_from_user(&connect_data, (char __user *)data,
482
- sizeof(struct mei_connect_client_data))) {
670
+ if (copy_from_user(&conn, (char __user *)data, sizeof(conn))) {
671
+ dev_dbg(dev->dev, "failed to copy data from userland\n");
672
+ rets = -EFAULT;
673
+ goto out;
674
+ }
675
+ cl_uuid = &conn.in_client_uuid;
676
+ props = &conn.out_client_properties;
677
+ vtag = 0;
678
+
679
+ rets = mei_vt_support_check(dev, cl_uuid);
680
+ if (rets == -ENOTTY)
681
+ goto out;
682
+ if (!rets)
683
+ rets = mei_ioctl_connect_vtag(file, cl_uuid, props,
684
+ vtag);
685
+ else
686
+ rets = mei_ioctl_connect_client(file, cl_uuid, props);
687
+ if (rets)
688
+ goto out;
689
+
690
+ /* if all is ok, copying the data back to user. */
691
+ if (copy_to_user((char __user *)data, &conn, sizeof(conn))) {
692
+ dev_dbg(dev->dev, "failed to copy data to userland\n");
693
+ rets = -EFAULT;
694
+ goto out;
695
+ }
696
+
697
+ break;
698
+
699
+ case IOCTL_MEI_CONNECT_CLIENT_VTAG:
700
+ dev_dbg(dev->dev, "IOCTL_MEI_CONNECT_CLIENT_VTAG\n");
701
+ if (copy_from_user(&conn_vtag, (char __user *)data,
702
+ sizeof(conn_vtag))) {
483703 dev_dbg(dev->dev, "failed to copy data from userland\n");
484704 rets = -EFAULT;
485705 goto out;
486706 }
487707
488
- rets = mei_ioctl_connect_client(file, &connect_data);
708
+ cl_uuid = &conn_vtag.connect.in_client_uuid;
709
+ props = &conn_vtag.out_client_properties;
710
+ vtag = conn_vtag.connect.vtag;
711
+
712
+ rets = mei_vt_support_check(dev, cl_uuid);
713
+ if (rets == -EOPNOTSUPP)
714
+ dev_dbg(dev->dev, "FW Client %pUl does not support vtags\n",
715
+ cl_uuid);
716
+ if (rets)
717
+ goto out;
718
+
719
+ if (!vtag) {
720
+ dev_dbg(dev->dev, "vtag can't be zero\n");
721
+ rets = -EINVAL;
722
+ goto out;
723
+ }
724
+
725
+ rets = mei_ioctl_connect_vtag(file, cl_uuid, props, vtag);
489726 if (rets)
490727 goto out;
491728
492729 /* if all is ok, copying the data back to user. */
493
- if (copy_to_user((char __user *)data, &connect_data,
494
- sizeof(struct mei_connect_client_data))) {
730
+ if (copy_to_user((char __user *)data, &conn_vtag,
731
+ sizeof(conn_vtag))) {
495732 dev_dbg(dev->dev, "failed to copy data to userland\n");
496733 rets = -EFAULT;
497734 goto out;
....@@ -536,24 +773,6 @@
536773 }
537774
538775 /**
539
- * mei_compat_ioctl - the compat IOCTL function
540
- *
541
- * @file: pointer to file structure
542
- * @cmd: ioctl command
543
- * @data: pointer to mei message structure
544
- *
545
- * Return: 0 on success , <0 on error
546
- */
547
-#ifdef CONFIG_COMPAT
548
-static long mei_compat_ioctl(struct file *file,
549
- unsigned int cmd, unsigned long data)
550
-{
551
- return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
552
-}
553
-#endif
554
-
555
-
556
-/**
557776 * mei_poll - the poll function
558777 *
559778 * @file: pointer to file structure
....@@ -593,7 +812,7 @@
593812 if (req_events & (EPOLLIN | EPOLLRDNORM)) {
594813 poll_wait(file, &cl->rx_wait, wait);
595814
596
- if (!list_empty(&cl->rd_completed))
815
+ if (mei_cl_read_cb(cl, file))
597816 mask |= EPOLLIN | EPOLLRDNORM;
598817 else
599818 mei_cl_read_start(cl, mei_cl_mtu(cl), file);
....@@ -702,6 +921,29 @@
702921
703922 return fasync_helper(fd, file, band, &cl->ev_async);
704923 }
924
+
925
+/**
926
+ * trc_show - mei device trc attribute show method
927
+ *
928
+ * @device: device pointer
929
+ * @attr: attribute pointer
930
+ * @buf: char out buffer
931
+ *
932
+ * Return: number of the bytes printed into buf or error
933
+ */
934
+static ssize_t trc_show(struct device *device,
935
+ struct device_attribute *attr, char *buf)
936
+{
937
+ struct mei_device *dev = dev_get_drvdata(device);
938
+ u32 trc;
939
+ int ret;
940
+
941
+ ret = mei_trc_status(dev, &trc);
942
+ if (ret)
943
+ return ret;
944
+ return sprintf(buf, "%08X\n", trc);
945
+}
946
+static DEVICE_ATTR_RO(trc);
705947
706948 /**
707949 * fw_status_show - mei device fw_status attribute show method
....@@ -838,12 +1080,84 @@
8381080 }
8391081 static DEVICE_ATTR_RO(fw_ver);
8401082
1083
+/**
1084
+ * dev_state_show - display device state
1085
+ *
1086
+ * @device: device pointer
1087
+ * @attr: attribute pointer
1088
+ * @buf: char out buffer
1089
+ *
1090
+ * Return: number of the bytes printed into buf or error
1091
+ */
1092
+static ssize_t dev_state_show(struct device *device,
1093
+ struct device_attribute *attr, char *buf)
1094
+{
1095
+ struct mei_device *dev = dev_get_drvdata(device);
1096
+ enum mei_dev_state dev_state;
1097
+
1098
+ mutex_lock(&dev->device_lock);
1099
+ dev_state = dev->dev_state;
1100
+ mutex_unlock(&dev->device_lock);
1101
+
1102
+ return sprintf(buf, "%s", mei_dev_state_str(dev_state));
1103
+}
1104
+static DEVICE_ATTR_RO(dev_state);
1105
+
1106
+/**
1107
+ * dev_set_devstate: set to new device state and notify sysfs file.
1108
+ *
1109
+ * @dev: mei_device
1110
+ * @state: new device state
1111
+ */
1112
+void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state)
1113
+{
1114
+ struct device *clsdev;
1115
+
1116
+ if (dev->dev_state == state)
1117
+ return;
1118
+
1119
+ dev->dev_state = state;
1120
+
1121
+ clsdev = class_find_device_by_devt(mei_class, dev->cdev.dev);
1122
+ if (clsdev) {
1123
+ sysfs_notify(&clsdev->kobj, NULL, "dev_state");
1124
+ put_device(clsdev);
1125
+ }
1126
+}
1127
+
1128
+/**
1129
+ * kind_show - display device kind
1130
+ *
1131
+ * @device: device pointer
1132
+ * @attr: attribute pointer
1133
+ * @buf: char out buffer
1134
+ *
1135
+ * Return: number of the bytes printed into buf or error
1136
+ */
1137
+static ssize_t kind_show(struct device *device,
1138
+ struct device_attribute *attr, char *buf)
1139
+{
1140
+ struct mei_device *dev = dev_get_drvdata(device);
1141
+ ssize_t ret;
1142
+
1143
+ if (dev->kind)
1144
+ ret = sprintf(buf, "%s\n", dev->kind);
1145
+ else
1146
+ ret = sprintf(buf, "%s\n", "mei");
1147
+
1148
+ return ret;
1149
+}
1150
+static DEVICE_ATTR_RO(kind);
1151
+
8411152 static struct attribute *mei_attrs[] = {
8421153 &dev_attr_fw_status.attr,
8431154 &dev_attr_hbm_ver.attr,
8441155 &dev_attr_hbm_ver_drv.attr,
8451156 &dev_attr_tx_queue_limit.attr,
8461157 &dev_attr_fw_ver.attr,
1158
+ &dev_attr_dev_state.attr,
1159
+ &dev_attr_trc.attr,
1160
+ &dev_attr_kind.attr,
8471161 NULL
8481162 };
8491163 ATTRIBUTE_GROUPS(mei);
....@@ -855,9 +1169,7 @@
8551169 .owner = THIS_MODULE,
8561170 .read = mei_read,
8571171 .unlocked_ioctl = mei_ioctl,
858
-#ifdef CONFIG_COMPAT
859
- .compat_ioctl = mei_compat_ioctl,
860
-#endif
1172
+ .compat_ioctl = compat_ptr_ioctl,
8611173 .open = mei_open,
8621174 .release = mei_release,
8631175 .write = mei_write,
....@@ -866,12 +1178,6 @@
8661178 .fasync = mei_fasync,
8671179 .llseek = no_llseek
8681180 };
869
-
870
-static struct class *mei_class;
871
-static dev_t mei_devt;
872
-#define MEI_MAX_DEVS MINORMASK
873
-static DEFINE_MUTEX(mei_minor_lock);
874
-static DEFINE_IDR(mei_idr);
8751181
8761182 /**
8771183 * mei_minor_get - obtain next free device minor number
....@@ -940,16 +1246,10 @@
9401246 goto err_dev_create;
9411247 }
9421248
943
- ret = mei_dbgfs_register(dev, dev_name(clsdev));
944
- if (ret) {
945
- dev_err(clsdev, "cannot register debugfs ret = %d\n", ret);
946
- goto err_dev_dbgfs;
947
- }
1249
+ mei_dbgfs_register(dev, dev_name(clsdev));
9481250
9491251 return 0;
9501252
951
-err_dev_dbgfs:
952
- device_destroy(mei_class, devno);
9531253 err_dev_create:
9541254 cdev_del(&dev->cdev);
9551255 err_dev_add: