2 * Intel MIC Platform Software Stack (MPSS)
4 * Copyright(c) 2015 Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
18 * Intel MIC Coprocessor State Management (COSM) Driver
22 #include <linux/module.h>
23 #include <linux/delay.h>
24 #include <linux/idr.h>
25 #include <linux/slab.h>
26 #include <linux/cred.h>
27 #include "cosm_main.h"
29 static const char cosm_driver_name
[] = "mic";
31 /* COSM ID allocator */
32 static struct ida g_cosm_ida
;
33 /* Class of MIC devices for sysfs accessibility. */
34 static struct class *g_cosm_class
;
35 /* Number of MIC devices */
36 static atomic_t g_num_dev
;
39 * cosm_hw_reset - Issue a HW reset for the MIC device
40 * @cdev: pointer to cosm_device instance
42 static void cosm_hw_reset(struct cosm_device
*cdev
, bool force
)
46 #define MIC_RESET_TO (45)
47 if (force
&& cdev
->hw_ops
->force_reset
)
48 cdev
->hw_ops
->force_reset(cdev
);
50 cdev
->hw_ops
->reset(cdev
);
52 for (i
= 0; i
< MIC_RESET_TO
; i
++) {
53 if (cdev
->hw_ops
->ready(cdev
)) {
54 cosm_set_state(cdev
, MIC_READY
);
58 * Resets typically take 10s of seconds to complete.
59 * Since an MMIO read is required to check if the
60 * firmware is ready or not, a 1 second delay works nicely.
64 cosm_set_state(cdev
, MIC_RESET_FAILED
);
68 * cosm_start - Start the MIC
69 * @cdev: pointer to cosm_device instance
71 * This function prepares an MIC for boot and initiates boot.
72 * RETURNS: An appropriate -ERRNO error value on error, or 0 for success.
74 int cosm_start(struct cosm_device
*cdev
)
76 const struct cred
*orig_cred
;
77 struct cred
*override_cred
;
80 mutex_lock(&cdev
->cosm_mutex
);
81 if (!cdev
->bootmode
) {
82 dev_err(&cdev
->dev
, "%s %d bootmode not set\n",
88 if (cdev
->state
!= MIC_READY
) {
89 dev_err(&cdev
->dev
, "%s %d MIC state not READY\n",
94 if (!cdev
->hw_ops
->ready(cdev
)) {
95 cosm_hw_reset(cdev
, false);
97 * The state will either be MIC_READY if the reset succeeded
98 * or MIC_RESET_FAILED if the firmware reset failed.
104 * Set credentials to root to allow non-root user to download initramsfs
105 * with 600 permissions
107 override_cred
= prepare_creds();
108 if (!override_cred
) {
109 dev_err(&cdev
->dev
, "%s %d prepare_creds failed\n",
114 override_cred
->fsuid
= GLOBAL_ROOT_UID
;
115 orig_cred
= override_creds(override_cred
);
117 rc
= cdev
->hw_ops
->start(cdev
, cdev
->index
);
119 revert_creds(orig_cred
);
120 put_cred(override_cred
);
125 * If linux is being booted, card is treated 'online' only
126 * when the scif interface in the card is up. If anything else
127 * is booted, we set card to 'online' immediately.
129 if (!strcmp(cdev
->bootmode
, "linux"))
130 cosm_set_state(cdev
, MIC_BOOTING
);
132 cosm_set_state(cdev
, MIC_ONLINE
);
134 mutex_unlock(&cdev
->cosm_mutex
);
136 dev_err(&cdev
->dev
, "cosm_start failed rc %d\n", rc
);
141 * cosm_stop - Prepare the MIC for reset and trigger reset
142 * @cdev: pointer to cosm_device instance
143 * @force: force a MIC to reset even if it is already reset and ready.
147 void cosm_stop(struct cosm_device
*cdev
, bool force
)
149 mutex_lock(&cdev
->cosm_mutex
);
150 if (cdev
->state
!= MIC_READY
|| force
) {
152 * Don't call hw_ops if they have been called previously.
153 * stop(..) calls device_unregister and will crash the system if
154 * called multiple times.
156 bool call_hw_ops
= cdev
->state
!= MIC_RESET_FAILED
&&
157 cdev
->state
!= MIC_READY
;
159 if (cdev
->state
!= MIC_RESETTING
)
160 cosm_set_state(cdev
, MIC_RESETTING
);
161 cdev
->heartbeat_watchdog_enable
= false;
163 cdev
->hw_ops
->stop(cdev
, force
);
164 cosm_hw_reset(cdev
, force
);
165 cosm_set_shutdown_status(cdev
, MIC_NOP
);
166 if (call_hw_ops
&& cdev
->hw_ops
->post_reset
)
167 cdev
->hw_ops
->post_reset(cdev
, cdev
->state
);
169 mutex_unlock(&cdev
->cosm_mutex
);
170 flush_work(&cdev
->scif_work
);
174 * cosm_reset_trigger_work - Trigger MIC reset
175 * @work: The work structure
177 * This work is scheduled whenever the host wants to reset the MIC.
179 static void cosm_reset_trigger_work(struct work_struct
*work
)
181 struct cosm_device
*cdev
= container_of(work
, struct cosm_device
,
183 cosm_stop(cdev
, false);
187 * cosm_reset - Schedule MIC reset
188 * @cdev: pointer to cosm_device instance
190 * RETURNS: An -EINVAL if the card is already READY or 0 for success.
192 int cosm_reset(struct cosm_device
*cdev
)
196 mutex_lock(&cdev
->cosm_mutex
);
197 if (cdev
->state
!= MIC_READY
) {
198 cosm_set_state(cdev
, MIC_RESETTING
);
199 schedule_work(&cdev
->reset_trigger_work
);
201 dev_err(&cdev
->dev
, "%s %d MIC is READY\n", __func__
, __LINE__
);
204 mutex_unlock(&cdev
->cosm_mutex
);
209 * cosm_shutdown - Initiate MIC shutdown.
210 * @cdev: pointer to cosm_device instance
214 int cosm_shutdown(struct cosm_device
*cdev
)
216 struct cosm_msg msg
= { .id
= COSM_MSG_SHUTDOWN
};
219 mutex_lock(&cdev
->cosm_mutex
);
220 if (cdev
->state
!= MIC_ONLINE
) {
222 dev_err(&cdev
->dev
, "%s %d skipping shutdown in state: %s\n",
223 __func__
, __LINE__
, cosm_state_string
[cdev
->state
]);
229 dev_err(&cdev
->dev
, "%s %d scif endpoint not connected rc %d\n",
230 __func__
, __LINE__
, rc
);
234 rc
= scif_send(cdev
->epd
, &msg
, sizeof(msg
), SCIF_SEND_BLOCK
);
236 dev_err(&cdev
->dev
, "%s %d scif_send failed rc %d\n",
237 __func__
, __LINE__
, rc
);
240 cdev
->heartbeat_watchdog_enable
= false;
241 cosm_set_state(cdev
, MIC_SHUTTING_DOWN
);
244 mutex_unlock(&cdev
->cosm_mutex
);
248 static int cosm_driver_probe(struct cosm_device
*cdev
)
252 /* Initialize SCIF server at first probe */
253 if (atomic_add_return(1, &g_num_dev
) == 1) {
254 rc
= cosm_scif_init();
258 mutex_init(&cdev
->cosm_mutex
);
259 INIT_WORK(&cdev
->reset_trigger_work
, cosm_reset_trigger_work
);
260 INIT_WORK(&cdev
->scif_work
, cosm_scif_work
);
261 cdev
->sysfs_heartbeat_enable
= true;
262 cosm_sysfs_init(cdev
);
263 cdev
->sdev
= device_create_with_groups(g_cosm_class
, cdev
->dev
.parent
,
264 MKDEV(0, cdev
->index
), cdev
, cdev
->attr_group
,
265 "mic%d", cdev
->index
);
266 if (IS_ERR(cdev
->sdev
)) {
267 rc
= PTR_ERR(cdev
->sdev
);
268 dev_err(&cdev
->dev
, "device_create_with_groups failed rc %d\n",
273 cdev
->state_sysfs
= sysfs_get_dirent(cdev
->sdev
->kobj
.sd
,
275 if (!cdev
->state_sysfs
) {
277 dev_err(&cdev
->dev
, "sysfs_get_dirent failed rc %d\n", rc
);
280 cosm_create_debug_dir(cdev
);
283 device_destroy(g_cosm_class
, MKDEV(0, cdev
->index
));
285 if (atomic_dec_and_test(&g_num_dev
))
290 static void cosm_driver_remove(struct cosm_device
*cdev
)
292 cosm_delete_debug_dir(cdev
);
293 sysfs_put(cdev
->state_sysfs
);
294 device_destroy(g_cosm_class
, MKDEV(0, cdev
->index
));
295 flush_work(&cdev
->reset_trigger_work
);
296 cosm_stop(cdev
, false);
297 if (atomic_dec_and_test(&g_num_dev
))
300 /* These sysfs entries might have allocated */
301 kfree(cdev
->cmdline
);
302 kfree(cdev
->firmware
);
303 kfree(cdev
->ramdisk
);
304 kfree(cdev
->bootmode
);
307 static int cosm_suspend(struct device
*dev
)
309 struct cosm_device
*cdev
= dev_to_cosm(dev
);
311 mutex_lock(&cdev
->cosm_mutex
);
312 switch (cdev
->state
) {
314 * Suspend/freeze hooks in userspace have already shutdown the card.
315 * Card should be 'ready' in most cases. It is however possible that
316 * some userspace application initiated a boot. In those cases, we
317 * simply reset the card.
321 case MIC_SHUTTING_DOWN
:
322 mutex_unlock(&cdev
->cosm_mutex
);
323 cosm_stop(cdev
, false);
326 mutex_unlock(&cdev
->cosm_mutex
);
332 static const struct dev_pm_ops cosm_pm_ops
= {
333 .suspend
= cosm_suspend
,
334 .freeze
= cosm_suspend
337 static struct cosm_driver cosm_driver
= {
339 .name
= KBUILD_MODNAME
,
340 .owner
= THIS_MODULE
,
343 .probe
= cosm_driver_probe
,
344 .remove
= cosm_driver_remove
347 static int __init
cosm_init(void)
353 g_cosm_class
= class_create(THIS_MODULE
, cosm_driver_name
);
354 if (IS_ERR(g_cosm_class
)) {
355 ret
= PTR_ERR(g_cosm_class
);
356 pr_err("class_create failed ret %d\n", ret
);
357 goto cleanup_debugfs
;
360 ida_init(&g_cosm_ida
);
361 ret
= cosm_register_driver(&cosm_driver
);
363 pr_err("cosm_register_driver failed ret %d\n", ret
);
368 ida_destroy(&g_cosm_ida
);
369 class_destroy(g_cosm_class
);
375 static void __exit
cosm_exit(void)
377 cosm_unregister_driver(&cosm_driver
);
378 ida_destroy(&g_cosm_ida
);
379 class_destroy(g_cosm_class
);
383 module_init(cosm_init
);
384 module_exit(cosm_exit
);
386 MODULE_AUTHOR("Intel Corporation");
387 MODULE_DESCRIPTION("Intel(R) MIC Coprocessor State Management (COSM) Driver");
388 MODULE_LICENSE("GPL v2");