Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Intel MIC Platform Software Stack (MPSS) |
| 3 | * |
| 4 | * Copyright(c) 2013 Intel Corporation. |
| 5 | * |
| 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. |
| 9 | * |
| 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. |
| 14 | * |
| 15 | * The full GNU General Public License is included in this distribution in |
| 16 | * the file called "COPYING". |
| 17 | * |
| 18 | * Intel MIC Host driver. |
| 19 | * |
| 20 | */ |
| 21 | #include <linux/delay.h> |
| 22 | #include <linux/firmware.h> |
Ashutosh Dixit | 4257922 | 2013-10-29 17:09:59 -0700 | [diff] [blame] | 23 | #include <linux/pci.h> |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 24 | |
| 25 | #include <linux/mic_common.h> |
Sudeep Dutt | 4aa7996 | 2013-09-27 09:49:42 -0700 | [diff] [blame] | 26 | #include "../common/mic_dev.h" |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 27 | #include "mic_device.h" |
| 28 | #include "mic_smpt.h" |
Ashutosh Dixit | f69bcbf | 2013-09-05 16:42:18 -0700 | [diff] [blame] | 29 | #include "mic_virtio.h" |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 30 | |
| 31 | /** |
| 32 | * mic_reset - Reset the MIC device. |
| 33 | * @mdev: pointer to mic_device instance |
| 34 | */ |
| 35 | static void mic_reset(struct mic_device *mdev) |
| 36 | { |
| 37 | int i; |
| 38 | |
| 39 | #define MIC_RESET_TO (45) |
| 40 | |
Wolfram Sang | 16735d0 | 2013-11-14 14:32:02 -0800 | [diff] [blame] | 41 | reinit_completion(&mdev->reset_wait); |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 42 | mdev->ops->reset_fw_ready(mdev); |
| 43 | mdev->ops->reset(mdev); |
| 44 | |
| 45 | for (i = 0; i < MIC_RESET_TO; i++) { |
| 46 | if (mdev->ops->is_fw_ready(mdev)) |
Dasaratharaman Chandramouli | af19049 | 2013-10-03 18:06:23 -0700 | [diff] [blame] | 47 | goto done; |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 48 | /* |
| 49 | * Resets typically take 10s of seconds to complete. |
| 50 | * Since an MMIO read is required to check if the |
| 51 | * firmware is ready or not, a 1 second delay works nicely. |
| 52 | */ |
| 53 | msleep(1000); |
| 54 | } |
| 55 | mic_set_state(mdev, MIC_RESET_FAILED); |
Dasaratharaman Chandramouli | af19049 | 2013-10-03 18:06:23 -0700 | [diff] [blame] | 56 | done: |
| 57 | complete_all(&mdev->reset_wait); |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | /* Initialize the MIC bootparams */ |
| 61 | void mic_bootparam_init(struct mic_device *mdev) |
| 62 | { |
| 63 | struct mic_bootparam *bootparam = mdev->dp; |
| 64 | |
Ashutosh Dixit | 173c072 | 2013-11-27 08:58:42 -0800 | [diff] [blame] | 65 | bootparam->magic = cpu_to_le32(MIC_MAGIC); |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 66 | bootparam->c2h_shutdown_db = mdev->shutdown_db; |
| 67 | bootparam->h2c_shutdown_db = -1; |
| 68 | bootparam->h2c_config_db = -1; |
| 69 | bootparam->shutdown_status = 0; |
| 70 | bootparam->shutdown_card = 0; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * mic_start - Start the MIC. |
| 75 | * @mdev: pointer to mic_device instance |
| 76 | * @buf: buffer containing boot string including firmware/ramdisk path. |
| 77 | * |
| 78 | * This function prepares an MIC for boot and initiates boot. |
| 79 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. |
| 80 | */ |
| 81 | int mic_start(struct mic_device *mdev, const char *buf) |
| 82 | { |
| 83 | int rc; |
| 84 | mutex_lock(&mdev->mic_mutex); |
| 85 | retry: |
| 86 | if (MIC_OFFLINE != mdev->state) { |
| 87 | rc = -EINVAL; |
| 88 | goto unlock_ret; |
| 89 | } |
| 90 | if (!mdev->ops->is_fw_ready(mdev)) { |
| 91 | mic_reset(mdev); |
| 92 | /* |
| 93 | * The state will either be MIC_OFFLINE if the reset succeeded |
| 94 | * or MIC_RESET_FAILED if the firmware reset failed. |
| 95 | */ |
| 96 | goto retry; |
| 97 | } |
| 98 | rc = mdev->ops->load_mic_fw(mdev, buf); |
| 99 | if (rc) |
| 100 | goto unlock_ret; |
| 101 | mic_smpt_restore(mdev); |
| 102 | mic_intr_restore(mdev); |
| 103 | mdev->intr_ops->enable_interrupts(mdev); |
| 104 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); |
| 105 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); |
| 106 | mdev->ops->send_firmware_intr(mdev); |
| 107 | mic_set_state(mdev, MIC_ONLINE); |
| 108 | unlock_ret: |
| 109 | mutex_unlock(&mdev->mic_mutex); |
| 110 | return rc; |
| 111 | } |
| 112 | |
| 113 | /** |
| 114 | * mic_stop - Prepare the MIC for reset and trigger reset. |
| 115 | * @mdev: pointer to mic_device instance |
| 116 | * @force: force a MIC to reset even if it is already offline. |
| 117 | * |
| 118 | * RETURNS: None. |
| 119 | */ |
| 120 | void mic_stop(struct mic_device *mdev, bool force) |
| 121 | { |
| 122 | mutex_lock(&mdev->mic_mutex); |
| 123 | if (MIC_OFFLINE != mdev->state || force) { |
Ashutosh Dixit | f69bcbf | 2013-09-05 16:42:18 -0700 | [diff] [blame] | 124 | mic_virtio_reset_devices(mdev); |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 125 | mic_bootparam_init(mdev); |
| 126 | mic_reset(mdev); |
| 127 | if (MIC_RESET_FAILED == mdev->state) |
| 128 | goto unlock; |
| 129 | mic_set_shutdown_status(mdev, MIC_NOP); |
Dasaratharaman Chandramouli | af19049 | 2013-10-03 18:06:23 -0700 | [diff] [blame] | 130 | if (MIC_SUSPENDED != mdev->state) |
| 131 | mic_set_state(mdev, MIC_OFFLINE); |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 132 | } |
| 133 | unlock: |
| 134 | mutex_unlock(&mdev->mic_mutex); |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * mic_shutdown - Initiate MIC shutdown. |
| 139 | * @mdev: pointer to mic_device instance |
| 140 | * |
| 141 | * RETURNS: None. |
| 142 | */ |
| 143 | void mic_shutdown(struct mic_device *mdev) |
| 144 | { |
| 145 | struct mic_bootparam *bootparam = mdev->dp; |
| 146 | s8 db = bootparam->h2c_shutdown_db; |
| 147 | |
| 148 | mutex_lock(&mdev->mic_mutex); |
| 149 | if (MIC_ONLINE == mdev->state && db != -1) { |
| 150 | bootparam->shutdown_card = 1; |
| 151 | mdev->ops->send_intr(mdev, db); |
| 152 | mic_set_state(mdev, MIC_SHUTTING_DOWN); |
| 153 | } |
| 154 | mutex_unlock(&mdev->mic_mutex); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * mic_shutdown_work - Handle shutdown interrupt from MIC. |
| 159 | * @work: The work structure. |
| 160 | * |
| 161 | * This work is scheduled whenever the host has received a shutdown |
| 162 | * interrupt from the MIC. |
| 163 | */ |
| 164 | void mic_shutdown_work(struct work_struct *work) |
| 165 | { |
| 166 | struct mic_device *mdev = container_of(work, struct mic_device, |
| 167 | shutdown_work); |
| 168 | struct mic_bootparam *bootparam = mdev->dp; |
| 169 | |
| 170 | mutex_lock(&mdev->mic_mutex); |
| 171 | mic_set_shutdown_status(mdev, bootparam->shutdown_status); |
| 172 | bootparam->shutdown_status = 0; |
Dasaratharaman Chandramouli | af19049 | 2013-10-03 18:06:23 -0700 | [diff] [blame] | 173 | |
| 174 | /* |
| 175 | * if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not |
| 176 | * change the state here so as to prevent users from booting the card |
| 177 | * during and after the suspend operation. |
| 178 | */ |
| 179 | if (MIC_SHUTTING_DOWN != mdev->state && |
| 180 | MIC_SUSPENDED != mdev->state) |
Sudeep Dutt | 3a6a920 | 2013-09-05 16:41:55 -0700 | [diff] [blame] | 181 | mic_set_state(mdev, MIC_SHUTTING_DOWN); |
| 182 | mutex_unlock(&mdev->mic_mutex); |
| 183 | } |
| 184 | |
| 185 | /** |
| 186 | * mic_reset_trigger_work - Trigger MIC reset. |
| 187 | * @work: The work structure. |
| 188 | * |
| 189 | * This work is scheduled whenever the host wants to reset the MIC. |
| 190 | */ |
| 191 | void mic_reset_trigger_work(struct work_struct *work) |
| 192 | { |
| 193 | struct mic_device *mdev = container_of(work, struct mic_device, |
| 194 | reset_trigger_work); |
| 195 | |
| 196 | mic_stop(mdev, false); |
| 197 | } |
Dasaratharaman Chandramouli | af19049 | 2013-10-03 18:06:23 -0700 | [diff] [blame] | 198 | |
| 199 | /** |
| 200 | * mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate |
| 201 | * event. |
| 202 | * @mdev: pointer to mic_device instance |
| 203 | * |
| 204 | * RETURNS: None. |
| 205 | */ |
| 206 | void mic_complete_resume(struct mic_device *mdev) |
| 207 | { |
| 208 | if (mdev->state != MIC_SUSPENDED) { |
| 209 | dev_warn(mdev->sdev->parent, "state %d should be %d\n", |
| 210 | mdev->state, MIC_SUSPENDED); |
| 211 | return; |
| 212 | } |
| 213 | |
| 214 | /* Make sure firmware is ready */ |
| 215 | if (!mdev->ops->is_fw_ready(mdev)) |
| 216 | mic_stop(mdev, true); |
| 217 | |
| 218 | mutex_lock(&mdev->mic_mutex); |
| 219 | mic_set_state(mdev, MIC_OFFLINE); |
| 220 | mutex_unlock(&mdev->mic_mutex); |
| 221 | } |
| 222 | |
| 223 | /** |
| 224 | * mic_prepare_suspend - Handle suspend notification for the MIC device. |
| 225 | * @mdev: pointer to mic_device instance |
| 226 | * |
| 227 | * RETURNS: None. |
| 228 | */ |
| 229 | void mic_prepare_suspend(struct mic_device *mdev) |
| 230 | { |
| 231 | int rc; |
| 232 | |
| 233 | #define MIC_SUSPEND_TIMEOUT (60 * HZ) |
| 234 | |
| 235 | mutex_lock(&mdev->mic_mutex); |
| 236 | switch (mdev->state) { |
| 237 | case MIC_OFFLINE: |
| 238 | /* |
| 239 | * Card is already offline. Set state to MIC_SUSPENDED |
| 240 | * to prevent users from booting the card. |
| 241 | */ |
| 242 | mic_set_state(mdev, MIC_SUSPENDED); |
| 243 | mutex_unlock(&mdev->mic_mutex); |
| 244 | break; |
| 245 | case MIC_ONLINE: |
| 246 | /* |
| 247 | * Card is online. Set state to MIC_SUSPENDING and notify |
| 248 | * MIC user space daemon which will issue card |
| 249 | * shutdown and reset. |
| 250 | */ |
| 251 | mic_set_state(mdev, MIC_SUSPENDING); |
| 252 | mutex_unlock(&mdev->mic_mutex); |
| 253 | rc = wait_for_completion_timeout(&mdev->reset_wait, |
| 254 | MIC_SUSPEND_TIMEOUT); |
| 255 | /* Force reset the card if the shutdown completion timed out */ |
| 256 | if (!rc) { |
| 257 | mutex_lock(&mdev->mic_mutex); |
| 258 | mic_set_state(mdev, MIC_SUSPENDED); |
| 259 | mutex_unlock(&mdev->mic_mutex); |
| 260 | mic_stop(mdev, true); |
| 261 | } |
| 262 | break; |
| 263 | case MIC_SHUTTING_DOWN: |
| 264 | /* |
| 265 | * Card is shutting down. Set state to MIC_SUSPENDED |
| 266 | * to prevent further boot of the card. |
| 267 | */ |
| 268 | mic_set_state(mdev, MIC_SUSPENDED); |
| 269 | mutex_unlock(&mdev->mic_mutex); |
| 270 | rc = wait_for_completion_timeout(&mdev->reset_wait, |
| 271 | MIC_SUSPEND_TIMEOUT); |
| 272 | /* Force reset the card if the shutdown completion timed out */ |
| 273 | if (!rc) |
| 274 | mic_stop(mdev, true); |
| 275 | break; |
| 276 | default: |
| 277 | mutex_unlock(&mdev->mic_mutex); |
| 278 | break; |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | /** |
| 283 | * mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown. |
| 284 | * @mdev: pointer to mic_device instance |
| 285 | * |
| 286 | * RETURNS: None. |
| 287 | */ |
| 288 | void mic_suspend(struct mic_device *mdev) |
| 289 | { |
| 290 | struct mic_bootparam *bootparam = mdev->dp; |
| 291 | s8 db = bootparam->h2c_shutdown_db; |
| 292 | |
| 293 | mutex_lock(&mdev->mic_mutex); |
| 294 | if (MIC_SUSPENDING == mdev->state && db != -1) { |
| 295 | bootparam->shutdown_card = 1; |
| 296 | mdev->ops->send_intr(mdev, db); |
| 297 | mic_set_state(mdev, MIC_SUSPENDED); |
| 298 | } |
| 299 | mutex_unlock(&mdev->mic_mutex); |
| 300 | } |