1 /* 2 * 3 * Intel Management Engine Interface (Intel MEI) Linux driver 4 * Copyright (c) 2003-2012, 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 * 15 */ 16 17 #include <linux/export.h> 18 #include <linux/pci.h> 19 #include <linux/sched.h> 20 #include <linux/wait.h> 21 #include <linux/delay.h> 22 23 #include <linux/mei.h> 24 25 #include "mei_dev.h" 26 #include "hbm.h" 27 #include "client.h" 28 29 const char *mei_dev_state_str(int state) 30 { 31 #define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state 32 switch (state) { 33 MEI_DEV_STATE(INITIALIZING); 34 MEI_DEV_STATE(INIT_CLIENTS); 35 MEI_DEV_STATE(ENABLED); 36 MEI_DEV_STATE(RESETTING); 37 MEI_DEV_STATE(DISABLED); 38 MEI_DEV_STATE(POWER_DOWN); 39 MEI_DEV_STATE(POWER_UP); 40 default: 41 return "unknown"; 42 } 43 #undef MEI_DEV_STATE 44 } 45 46 void mei_device_init(struct mei_device *dev) 47 { 48 /* setup our list array */ 49 INIT_LIST_HEAD(&dev->file_list); 50 INIT_LIST_HEAD(&dev->device_list); 51 mutex_init(&dev->device_lock); 52 init_waitqueue_head(&dev->wait_hw_ready); 53 init_waitqueue_head(&dev->wait_recvd_msg); 54 init_waitqueue_head(&dev->wait_stop_wd); 55 dev->dev_state = MEI_DEV_INITIALIZING; 56 57 mei_io_list_init(&dev->read_list); 58 mei_io_list_init(&dev->write_list); 59 mei_io_list_init(&dev->write_waiting_list); 60 mei_io_list_init(&dev->ctrl_wr_list); 61 mei_io_list_init(&dev->ctrl_rd_list); 62 63 INIT_DELAYED_WORK(&dev->timer_work, mei_timer); 64 INIT_WORK(&dev->init_work, mei_host_client_init); 65 66 INIT_LIST_HEAD(&dev->wd_cl.link); 67 INIT_LIST_HEAD(&dev->iamthif_cl.link); 68 mei_io_list_init(&dev->amthif_cmd_list); 69 mei_io_list_init(&dev->amthif_rd_complete_list); 70 71 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); 72 dev->open_handle_count = 0; 73 74 /* 75 * Reserving the first client ID 76 * 0: Reserved for MEI Bus Message communications 77 */ 78 bitmap_set(dev->host_clients_map, 0, 1); 79 } 80 EXPORT_SYMBOL_GPL(mei_device_init); 81 82 /** 83 * mei_start - initializes host and fw to start work. 84 * 85 * @dev: the device structure 86 * 87 * returns 0 on success, <0 on failure. 88 */ 89 int mei_start(struct mei_device *dev) 90 { 91 mutex_lock(&dev->device_lock); 92 93 /* acknowledge interrupt and stop interupts */ 94 mei_clear_interrupts(dev); 95 96 mei_hw_config(dev); 97 98 dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); 99 100 mei_reset(dev, 1); 101 102 if (mei_hbm_start_wait(dev)) { 103 dev_err(&dev->pdev->dev, "HBM haven't started"); 104 goto err; 105 } 106 107 if (!mei_host_is_ready(dev)) { 108 dev_err(&dev->pdev->dev, "host is not ready.\n"); 109 goto err; 110 } 111 112 if (!mei_hw_is_ready(dev)) { 113 dev_err(&dev->pdev->dev, "ME is not ready.\n"); 114 goto err; 115 } 116 117 if (!mei_hbm_version_is_supported(dev)) { 118 dev_dbg(&dev->pdev->dev, "MEI start failed.\n"); 119 goto err; 120 } 121 122 dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); 123 124 mutex_unlock(&dev->device_lock); 125 return 0; 126 err: 127 dev_err(&dev->pdev->dev, "link layer initialization failed.\n"); 128 dev->dev_state = MEI_DEV_DISABLED; 129 mutex_unlock(&dev->device_lock); 130 return -ENODEV; 131 } 132 EXPORT_SYMBOL_GPL(mei_start); 133 134 /** 135 * mei_reset - resets host and fw. 136 * 137 * @dev: the device structure 138 * @interrupts_enabled: if interrupt should be enabled after reset. 139 */ 140 void mei_reset(struct mei_device *dev, int interrupts_enabled) 141 { 142 bool unexpected; 143 int ret; 144 145 unexpected = (dev->dev_state != MEI_DEV_INITIALIZING && 146 dev->dev_state != MEI_DEV_DISABLED && 147 dev->dev_state != MEI_DEV_POWER_DOWN && 148 dev->dev_state != MEI_DEV_POWER_UP); 149 150 if (unexpected) 151 dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", 152 mei_dev_state_str(dev->dev_state)); 153 154 ret = mei_hw_reset(dev, interrupts_enabled); 155 if (ret) { 156 dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); 157 interrupts_enabled = false; 158 dev->dev_state = MEI_DEV_DISABLED; 159 } 160 161 dev->hbm_state = MEI_HBM_IDLE; 162 163 if (dev->dev_state != MEI_DEV_INITIALIZING && 164 dev->dev_state != MEI_DEV_POWER_UP) { 165 if (dev->dev_state != MEI_DEV_DISABLED && 166 dev->dev_state != MEI_DEV_POWER_DOWN) 167 dev->dev_state = MEI_DEV_RESETTING; 168 169 /* remove all waiting requests */ 170 mei_cl_all_write_clear(dev); 171 172 mei_cl_all_disconnect(dev); 173 174 /* wake up all readings so they can be interrupted */ 175 mei_cl_all_wakeup(dev); 176 177 /* remove entry if already in list */ 178 dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); 179 mei_cl_unlink(&dev->wd_cl); 180 mei_cl_unlink(&dev->iamthif_cl); 181 mei_amthif_reset_params(dev); 182 memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); 183 } 184 185 /* we're already in reset, cancel the init timer */ 186 dev->init_clients_timer = 0; 187 188 dev->me_clients_num = 0; 189 dev->rd_msg_hdr = 0; 190 dev->wd_pending = false; 191 192 if (!interrupts_enabled) { 193 dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); 194 return; 195 } 196 197 ret = mei_hw_start(dev); 198 if (ret) { 199 dev_err(&dev->pdev->dev, "hw_start failed disabling the device\n"); 200 dev->dev_state = MEI_DEV_DISABLED; 201 return; 202 } 203 204 dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); 205 /* link is established * start sending messages. */ 206 207 dev->dev_state = MEI_DEV_INIT_CLIENTS; 208 209 mei_hbm_start_req(dev); 210 211 } 212 EXPORT_SYMBOL_GPL(mei_reset); 213 214 void mei_stop(struct mei_device *dev) 215 { 216 dev_dbg(&dev->pdev->dev, "stopping the device.\n"); 217 218 flush_scheduled_work(); 219 220 mutex_lock(&dev->device_lock); 221 222 cancel_delayed_work(&dev->timer_work); 223 224 mei_wd_stop(dev); 225 226 mei_nfc_host_exit(); 227 228 dev->dev_state = MEI_DEV_POWER_DOWN; 229 mei_reset(dev, 0); 230 231 mutex_unlock(&dev->device_lock); 232 233 mei_watchdog_unregister(dev); 234 } 235 EXPORT_SYMBOL_GPL(mei_stop); 236 237 238 239