Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Intel MIC Host Driver Interrupt/SMPT support.

This patch enables the following features:
a) MSIx, MSI and legacy interrupt support.
b) System Memory Page Table(SMPT) support. SMPT enables system memory
access from the card. On X100 devices the host can program 32 SMPT
registers each capable of accessing 16GB of system memory
address space from X100 devices. The registers can thereby be used
to access a cumulative 512GB of system memory address space from
X100 devices at any point in time.

Co-author: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Caz Yokoyama <Caz.Yokoyama@intel.com>
Signed-off-by: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com>
Signed-off-by: Nikhil Rao <nikhil.rao@intel.com>
Signed-off-by: Harshavardhan R Kharche <harshavardhan.r.kharche@intel.com>
Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com>
Acked-by: Yaozu (Eddie) Dong <eddie.dong@intel.com>
Reviewed-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dasaratharaman Chandramouli and committed by
Greg Kroah-Hartman
a01e28f6 b170d8ce

+1638 -2
+2
drivers/misc/mic/host/Makefile
··· 6 6 mic_host-objs := mic_main.o 7 7 mic_host-objs += mic_x100.o 8 8 mic_host-objs += mic_sysfs.o 9 + mic_host-objs += mic_smpt.o 10 + mic_host-objs += mic_intr.o
+21
drivers/misc/mic/host/mic_device.h
··· 21 21 #ifndef _MIC_DEVICE_H_ 22 22 #define _MIC_DEVICE_H_ 23 23 24 + #include <linux/idr.h> 25 + 26 + #include "mic_intr.h" 27 + 24 28 /* The maximum number of MIC devices supported in a single host system. */ 25 29 #define MIC_MAX_NUM_DEVS 256 26 30 ··· 57 53 * @stepping: Stepping ID. 58 54 * @attr_group: Pointer to list of sysfs attribute groups. 59 55 * @sdev: Device for sysfs entries. 56 + * @mic_mutex: Mutex for synchronizing access to mic_device. 57 + * @intr_ops: HW specific interrupt operations. 58 + * @smpt_ops: Hardware specific SMPT operations. 59 + * @smpt: MIC SMPT information. 60 + * @intr_info: H/W specific interrupt information. 61 + * @irq_info: The OS specific irq information 60 62 */ 61 63 struct mic_device { 62 64 struct mic_mw mmio; ··· 73 63 enum mic_stepping stepping; 74 64 const struct attribute_group **attr_group; 75 65 struct device *sdev; 66 + struct mutex mic_mutex; 67 + struct mic_hw_intr_ops *intr_ops; 68 + struct mic_smpt_ops *smpt_ops; 69 + struct mic_smpt_info *smpt; 70 + struct mic_intr_info *intr_info; 71 + struct mic_irq_info irq_info; 76 72 }; 77 73 78 74 /** ··· 87 71 * @mmio_bar: MMIO bar resource number. 88 72 * @read_spad: Read from scratch pad register. 89 73 * @write_spad: Write to scratch pad register. 74 + * @send_intr: Send an interrupt for a particular doorbell on the card. 75 + * @ack_interrupt: Hardware specific operations to ack the h/w on 76 + * receipt of an interrupt. 90 77 */ 91 78 struct mic_hw_ops { 92 79 u8 aper_bar; 93 80 u8 mmio_bar; 94 81 u32 (*read_spad)(struct mic_device *mdev, unsigned int idx); 95 82 void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val); 83 + void (*send_intr)(struct mic_device *mdev, int doorbell); 84 + u32 (*ack_interrupt)(struct mic_device *mdev); 96 85 }; 97 86 98 87 /**
+628
drivers/misc/mic/host/mic_intr.c
··· 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/pci.h> 22 + #include <linux/interrupt.h> 23 + 24 + #include "../common/mic_device.h" 25 + #include "mic_device.h" 26 + 27 + /* 28 + * mic_invoke_callback - Invoke callback functions registered for 29 + * the corresponding source id. 30 + * 31 + * @mdev: pointer to the mic_device instance 32 + * @idx: The interrupt source id. 33 + * 34 + * Returns none. 35 + */ 36 + static inline void mic_invoke_callback(struct mic_device *mdev, int idx) 37 + { 38 + struct mic_intr_cb *intr_cb; 39 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 40 + struct pci_dev, dev); 41 + 42 + spin_lock(&mdev->irq_info.mic_intr_lock); 43 + list_for_each_entry(intr_cb, &mdev->irq_info.cb_list[idx], list) 44 + if (intr_cb->func) 45 + intr_cb->func(pdev->irq, intr_cb->data); 46 + spin_unlock(&mdev->irq_info.mic_intr_lock); 47 + } 48 + 49 + /** 50 + * mic_interrupt - Generic interrupt handler for 51 + * MSI and INTx based interrupts. 52 + */ 53 + static irqreturn_t mic_interrupt(int irq, void *dev) 54 + { 55 + struct mic_device *mdev = dev; 56 + struct mic_intr_info *info = mdev->intr_info; 57 + u32 mask; 58 + int i; 59 + 60 + mask = mdev->ops->ack_interrupt(mdev); 61 + if (!mask) 62 + return IRQ_NONE; 63 + 64 + for (i = info->intr_start_idx[MIC_INTR_DB]; 65 + i < info->intr_len[MIC_INTR_DB]; i++) 66 + if (mask & BIT(i)) 67 + mic_invoke_callback(mdev, i); 68 + 69 + return IRQ_HANDLED; 70 + } 71 + 72 + /* Return the interrupt offset from the index. Index is 0 based. */ 73 + static u16 mic_map_src_to_offset(struct mic_device *mdev, 74 + int intr_src, enum mic_intr_type type) { 75 + 76 + if (type >= MIC_NUM_INTR_TYPES) 77 + return MIC_NUM_OFFSETS; 78 + if (intr_src >= mdev->intr_info->intr_len[type]) 79 + return MIC_NUM_OFFSETS; 80 + 81 + return mdev->intr_info->intr_start_idx[type] + intr_src; 82 + } 83 + 84 + /* Return next available msix_entry. */ 85 + static struct msix_entry *mic_get_available_vector(struct mic_device *mdev) 86 + { 87 + int i; 88 + struct mic_irq_info *info = &mdev->irq_info; 89 + 90 + for (i = 0; i < info->num_vectors; i++) 91 + if (!info->mic_msi_map[i]) 92 + return &info->msix_entries[i]; 93 + return NULL; 94 + } 95 + 96 + /** 97 + * mic_register_intr_callback - Register a callback handler for the 98 + * given source id. 99 + * 100 + * @mdev: pointer to the mic_device instance 101 + * @idx: The source id to be registered. 102 + * @func: The function to be called when the source id receives 103 + * the interrupt. 104 + * @data: Private data of the requester. 105 + * Return the callback structure that was registered or an 106 + * appropriate error on failure. 107 + */ 108 + static struct mic_intr_cb *mic_register_intr_callback(struct mic_device *mdev, 109 + u8 idx, irqreturn_t (*func) (int irq, void *dev), 110 + void *data) 111 + { 112 + struct mic_intr_cb *intr_cb; 113 + unsigned long flags; 114 + int rc; 115 + intr_cb = kmalloc(sizeof(struct mic_intr_cb), GFP_KERNEL); 116 + 117 + if (!intr_cb) 118 + return ERR_PTR(-ENOMEM); 119 + 120 + intr_cb->func = func; 121 + intr_cb->data = data; 122 + intr_cb->cb_id = ida_simple_get(&mdev->irq_info.cb_ida, 123 + 0, 0, GFP_KERNEL); 124 + if (intr_cb->cb_id < 0) { 125 + rc = intr_cb->cb_id; 126 + goto ida_fail; 127 + } 128 + 129 + spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 130 + list_add_tail(&intr_cb->list, &mdev->irq_info.cb_list[idx]); 131 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 132 + 133 + return intr_cb; 134 + ida_fail: 135 + kfree(intr_cb); 136 + return ERR_PTR(rc); 137 + } 138 + 139 + /** 140 + * mic_unregister_intr_callback - Unregister the callback handler 141 + * identified by its callback id. 142 + * 143 + * @mdev: pointer to the mic_device instance 144 + * @idx: The callback structure id to be unregistered. 145 + * Return the source id that was unregistered or MIC_NUM_OFFSETS if no 146 + * such callback handler was found. 147 + */ 148 + static u8 mic_unregister_intr_callback(struct mic_device *mdev, u32 idx) 149 + { 150 + struct list_head *pos, *tmp; 151 + struct mic_intr_cb *intr_cb; 152 + unsigned long flags; 153 + int i; 154 + 155 + for (i = 0; i < MIC_NUM_OFFSETS; i++) { 156 + spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 157 + list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { 158 + intr_cb = list_entry(pos, struct mic_intr_cb, list); 159 + if (intr_cb->cb_id == idx) { 160 + list_del(pos); 161 + ida_simple_remove(&mdev->irq_info.cb_ida, 162 + intr_cb->cb_id); 163 + kfree(intr_cb); 164 + spin_unlock_irqrestore( 165 + &mdev->irq_info.mic_intr_lock, flags); 166 + return i; 167 + } 168 + } 169 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 170 + } 171 + return MIC_NUM_OFFSETS; 172 + } 173 + 174 + /** 175 + * mic_setup_msix - Initializes MSIx interrupts. 176 + * 177 + * @mdev: pointer to mic_device instance 178 + * 179 + * 180 + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 181 + */ 182 + static int mic_setup_msix(struct mic_device *mdev, struct pci_dev *pdev) 183 + { 184 + int rc, i; 185 + 186 + mdev->irq_info.msix_entries = kmalloc(sizeof(struct msix_entry) * 187 + MIC_MIN_MSIX, GFP_KERNEL); 188 + if (!mdev->irq_info.msix_entries) { 189 + rc = -ENOMEM; 190 + goto err_nomem1; 191 + } 192 + 193 + for (i = 0; i < MIC_MIN_MSIX; i++) 194 + mdev->irq_info.msix_entries[i].entry = i; 195 + 196 + rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries, 197 + MIC_MIN_MSIX); 198 + if (rc) { 199 + dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc); 200 + goto err_enable_msix; 201 + } 202 + 203 + mdev->irq_info.num_vectors = MIC_MIN_MSIX; 204 + mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * 205 + mdev->irq_info.num_vectors), GFP_KERNEL); 206 + 207 + if (!mdev->irq_info.mic_msi_map) { 208 + rc = -ENOMEM; 209 + goto err_nomem2; 210 + } 211 + 212 + dev_dbg(mdev->sdev->parent, 213 + "%d MSIx irqs setup\n", mdev->irq_info.num_vectors); 214 + return 0; 215 + err_nomem2: 216 + pci_disable_msix(pdev); 217 + err_enable_msix: 218 + kfree(mdev->irq_info.msix_entries); 219 + err_nomem1: 220 + mdev->irq_info.num_vectors = 0; 221 + return rc; 222 + } 223 + 224 + /** 225 + * mic_setup_callbacks - Initialize data structures needed 226 + * to handle callbacks. 227 + * 228 + * @mdev: pointer to mic_device instance 229 + */ 230 + static int mic_setup_callbacks(struct mic_device *mdev) 231 + { 232 + int i; 233 + 234 + mdev->irq_info.cb_list = kmalloc(sizeof(struct list_head) * 235 + MIC_NUM_OFFSETS, GFP_KERNEL); 236 + if (!mdev->irq_info.cb_list) 237 + return -ENOMEM; 238 + 239 + for (i = 0; i < MIC_NUM_OFFSETS; i++) 240 + INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); 241 + ida_init(&mdev->irq_info.cb_ida); 242 + spin_lock_init(&mdev->irq_info.mic_intr_lock); 243 + return 0; 244 + } 245 + 246 + /** 247 + * mic_release_callbacks - Uninitialize data structures needed 248 + * to handle callbacks. 249 + * 250 + * @mdev: pointer to mic_device instance 251 + */ 252 + static void mic_release_callbacks(struct mic_device *mdev) 253 + { 254 + unsigned long flags; 255 + struct list_head *pos, *tmp; 256 + struct mic_intr_cb *intr_cb; 257 + int i; 258 + 259 + for (i = 0; i < MIC_NUM_OFFSETS; i++) { 260 + spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); 261 + 262 + if (list_empty(&mdev->irq_info.cb_list[i])) { 263 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, 264 + flags); 265 + break; 266 + } 267 + 268 + list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { 269 + intr_cb = list_entry(pos, struct mic_intr_cb, list); 270 + list_del(pos); 271 + ida_simple_remove(&mdev->irq_info.cb_ida, 272 + intr_cb->cb_id); 273 + kfree(intr_cb); 274 + } 275 + spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); 276 + } 277 + ida_destroy(&mdev->irq_info.cb_ida); 278 + kfree(mdev->irq_info.cb_list); 279 + } 280 + 281 + /** 282 + * mic_setup_msi - Initializes MSI interrupts. 283 + * 284 + * @mdev: pointer to mic_device instance 285 + * @pdev: PCI device structure 286 + * 287 + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 288 + */ 289 + static int mic_setup_msi(struct mic_device *mdev, struct pci_dev *pdev) 290 + { 291 + int rc; 292 + 293 + rc = pci_enable_msi(pdev); 294 + if (rc) { 295 + dev_dbg(&pdev->dev, "Error enabling MSI. rc = %d\n", rc); 296 + return rc; 297 + } 298 + 299 + mdev->irq_info.num_vectors = 1; 300 + mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * 301 + mdev->irq_info.num_vectors), GFP_KERNEL); 302 + 303 + if (!mdev->irq_info.mic_msi_map) { 304 + rc = -ENOMEM; 305 + goto err_nomem1; 306 + } 307 + 308 + rc = mic_setup_callbacks(mdev); 309 + if (rc) { 310 + dev_err(&pdev->dev, "Error setting up callbacks\n"); 311 + goto err_nomem2; 312 + } 313 + 314 + rc = request_irq(pdev->irq, mic_interrupt, 0 , "mic-msi", mdev); 315 + if (rc) { 316 + dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); 317 + goto err_irq_req_fail; 318 + } 319 + 320 + dev_dbg(&pdev->dev, "%d MSI irqs setup\n", mdev->irq_info.num_vectors); 321 + return 0; 322 + err_irq_req_fail: 323 + mic_release_callbacks(mdev); 324 + err_nomem2: 325 + kfree(mdev->irq_info.mic_msi_map); 326 + err_nomem1: 327 + pci_disable_msi(pdev); 328 + mdev->irq_info.num_vectors = 0; 329 + return rc; 330 + } 331 + 332 + /** 333 + * mic_setup_intx - Initializes legacy interrupts. 334 + * 335 + * @mdev: pointer to mic_device instance 336 + * @pdev: PCI device structure 337 + * 338 + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 339 + */ 340 + static int mic_setup_intx(struct mic_device *mdev, struct pci_dev *pdev) 341 + { 342 + int rc; 343 + 344 + pci_msi_off(pdev); 345 + 346 + /* Enable intx */ 347 + pci_intx(pdev, 1); 348 + rc = mic_setup_callbacks(mdev); 349 + if (rc) { 350 + dev_err(&pdev->dev, "Error setting up callbacks\n"); 351 + goto err_nomem; 352 + } 353 + 354 + rc = request_irq(pdev->irq, mic_interrupt, 355 + IRQF_SHARED, "mic-intx", mdev); 356 + if (rc) 357 + goto err; 358 + 359 + dev_dbg(&pdev->dev, "intx irq setup\n"); 360 + return 0; 361 + err: 362 + mic_release_callbacks(mdev); 363 + err_nomem: 364 + return rc; 365 + } 366 + 367 + /** 368 + * mic_next_db - Retrieve the next doorbell interrupt source id. 369 + * The id is picked sequentially from the available pool of 370 + * doorlbell ids. 371 + * 372 + * @mdev: pointer to the mic_device instance. 373 + * 374 + * Returns the next doorbell interrupt source. 375 + */ 376 + int mic_next_db(struct mic_device *mdev) 377 + { 378 + int next_db; 379 + 380 + next_db = mdev->irq_info.next_avail_src % 381 + mdev->intr_info->intr_len[MIC_INTR_DB]; 382 + mdev->irq_info.next_avail_src++; 383 + return next_db; 384 + } 385 + 386 + #define COOKIE_ID_SHIFT 16 387 + #define GET_ENTRY(cookie) ((cookie) & 0xFFFF) 388 + #define GET_OFFSET(cookie) ((cookie) >> COOKIE_ID_SHIFT) 389 + #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) 390 + 391 + /** 392 + * mic_request_irq - request an irq. mic_mutex needs 393 + * to be held before calling this function. 394 + * 395 + * @mdev: pointer to mic_device instance 396 + * @func: The callback function that handles the interrupt. 397 + * The function needs to call ack_interrupts 398 + * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. 399 + * @name: The ASCII name of the callee requesting the irq. 400 + * @data: private data that is returned back when calling the 401 + * function handler. 402 + * @intr_src: The source id of the requester. Its the doorbell id 403 + * for Doorbell interrupts and DMA channel id for DMA interrupts. 404 + * @type: The type of interrupt. Values defined in mic_intr_type 405 + * 406 + * returns: The cookie that is transparent to the caller. Passed 407 + * back when calling mic_free_irq. An appropriate error code 408 + * is returned on failure. Caller needs to use IS_ERR(return_val) 409 + * to check for failure and PTR_ERR(return_val) to obtained the 410 + * error code. 411 + * 412 + */ 413 + struct mic_irq *mic_request_irq(struct mic_device *mdev, 414 + irqreturn_t (*func)(int irq, void *dev), 415 + const char *name, void *data, int intr_src, 416 + enum mic_intr_type type) 417 + { 418 + u16 offset; 419 + int rc = 0; 420 + struct msix_entry *msix = NULL; 421 + unsigned long cookie = 0; 422 + u16 entry; 423 + struct mic_intr_cb *intr_cb; 424 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 425 + struct pci_dev, dev); 426 + 427 + offset = mic_map_src_to_offset(mdev, intr_src, type); 428 + if (offset >= MIC_NUM_OFFSETS) { 429 + dev_err(mdev->sdev->parent, 430 + "Error mapping index %d to a valid source id.\n", 431 + intr_src); 432 + rc = -EINVAL; 433 + goto err; 434 + } 435 + 436 + if (mdev->irq_info.num_vectors > 1) { 437 + msix = mic_get_available_vector(mdev); 438 + if (!msix) { 439 + dev_err(mdev->sdev->parent, 440 + "No MSIx vectors available for use.\n"); 441 + rc = -ENOSPC; 442 + goto err; 443 + } 444 + 445 + rc = request_irq(msix->vector, func, 0, name, data); 446 + if (rc) { 447 + dev_dbg(mdev->sdev->parent, 448 + "request irq failed rc = %d\n", rc); 449 + goto err; 450 + } 451 + entry = msix->entry; 452 + mdev->irq_info.mic_msi_map[entry] |= BIT(offset); 453 + mdev->intr_ops->program_msi_to_src_map(mdev, 454 + entry, offset, true); 455 + cookie = MK_COOKIE(entry, offset); 456 + dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", 457 + msix->vector, intr_src); 458 + } else { 459 + intr_cb = mic_register_intr_callback(mdev, 460 + offset, func, data); 461 + if (IS_ERR(intr_cb)) { 462 + dev_err(mdev->sdev->parent, 463 + "No available callback entries for use\n"); 464 + rc = PTR_ERR(intr_cb); 465 + goto err; 466 + } 467 + 468 + entry = 0; 469 + if (pci_dev_msi_enabled(pdev)) { 470 + mdev->irq_info.mic_msi_map[entry] |= (1 << offset); 471 + mdev->intr_ops->program_msi_to_src_map(mdev, 472 + entry, offset, true); 473 + } 474 + cookie = MK_COOKIE(entry, intr_cb->cb_id); 475 + dev_dbg(mdev->sdev->parent, "callback %d registered for src: %d\n", 476 + intr_cb->cb_id, intr_src); 477 + } 478 + return (struct mic_irq *)cookie; 479 + err: 480 + return ERR_PTR(rc); 481 + } 482 + 483 + /** 484 + * mic_free_irq - free irq. mic_mutex 485 + * needs to be held before calling this function. 486 + * 487 + * @mdev: pointer to mic_device instance 488 + * @cookie: cookie obtained during a successful call to mic_request_irq 489 + * @data: private data specified by the calling function during the 490 + * mic_request_irq 491 + * 492 + * returns: none. 493 + */ 494 + void mic_free_irq(struct mic_device *mdev, 495 + struct mic_irq *cookie, void *data) 496 + { 497 + u32 offset; 498 + u32 entry; 499 + u8 src_id; 500 + unsigned int irq; 501 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 502 + struct pci_dev, dev); 503 + 504 + entry = GET_ENTRY((unsigned long)cookie); 505 + offset = GET_OFFSET((unsigned long)cookie); 506 + if (mdev->irq_info.num_vectors > 1) { 507 + if (entry >= mdev->irq_info.num_vectors) { 508 + dev_warn(mdev->sdev->parent, 509 + "entry %d should be < num_irq %d\n", 510 + entry, mdev->irq_info.num_vectors); 511 + return; 512 + } 513 + irq = mdev->irq_info.msix_entries[entry].vector; 514 + free_irq(irq, data); 515 + mdev->irq_info.mic_msi_map[entry] &= ~(BIT(offset)); 516 + mdev->intr_ops->program_msi_to_src_map(mdev, 517 + entry, offset, false); 518 + 519 + dev_dbg(mdev->sdev->parent, "irq: %d freed\n", irq); 520 + } else { 521 + irq = pdev->irq; 522 + src_id = mic_unregister_intr_callback(mdev, offset); 523 + if (src_id >= MIC_NUM_OFFSETS) { 524 + dev_warn(mdev->sdev->parent, "Error unregistering callback\n"); 525 + return; 526 + } 527 + if (pci_dev_msi_enabled(pdev)) { 528 + mdev->irq_info.mic_msi_map[entry] &= ~(BIT(src_id)); 529 + mdev->intr_ops->program_msi_to_src_map(mdev, 530 + entry, src_id, false); 531 + } 532 + dev_dbg(mdev->sdev->parent, "callback %d unregistered for src: %d\n", 533 + offset, src_id); 534 + } 535 + } 536 + 537 + /** 538 + * mic_setup_interrupts - Initializes interrupts. 539 + * 540 + * @mdev: pointer to mic_device instance 541 + * @pdev: PCI device structure 542 + * 543 + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 544 + */ 545 + int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev) 546 + { 547 + int rc; 548 + 549 + rc = mic_setup_msix(mdev, pdev); 550 + if (!rc) 551 + goto done; 552 + 553 + rc = mic_setup_msi(mdev, pdev); 554 + if (!rc) 555 + goto done; 556 + 557 + rc = mic_setup_intx(mdev, pdev); 558 + if (rc) { 559 + dev_err(mdev->sdev->parent, "no usable interrupts\n"); 560 + return rc; 561 + } 562 + done: 563 + mdev->intr_ops->enable_interrupts(mdev); 564 + return 0; 565 + } 566 + 567 + /** 568 + * mic_free_interrupts - Frees interrupts setup by mic_setup_interrupts 569 + * 570 + * @mdev: pointer to mic_device instance 571 + * @pdev: PCI device structure 572 + * 573 + * returns none. 574 + */ 575 + void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev) 576 + { 577 + int i; 578 + 579 + mdev->intr_ops->disable_interrupts(mdev); 580 + if (mdev->irq_info.num_vectors > 1) { 581 + for (i = 0; i < mdev->irq_info.num_vectors; i++) { 582 + if (mdev->irq_info.mic_msi_map[i]) 583 + dev_warn(&pdev->dev, "irq %d may still be in use.\n", 584 + mdev->irq_info.msix_entries[i].vector); 585 + } 586 + kfree(mdev->irq_info.mic_msi_map); 587 + kfree(mdev->irq_info.msix_entries); 588 + pci_disable_msix(pdev); 589 + } else { 590 + if (pci_dev_msi_enabled(pdev)) { 591 + free_irq(pdev->irq, mdev); 592 + kfree(mdev->irq_info.mic_msi_map); 593 + pci_disable_msi(pdev); 594 + } else { 595 + free_irq(pdev->irq, mdev); 596 + } 597 + mic_release_callbacks(mdev); 598 + } 599 + } 600 + 601 + /** 602 + * mic_intr_restore - Restore MIC interrupt registers. 603 + * 604 + * @mdev: pointer to mic_device instance. 605 + * 606 + * Restore the interrupt registers to values previously 607 + * stored in the SW data structures. mic_mutex needs to 608 + * be held before calling this function. 609 + * 610 + * returns None. 611 + */ 612 + void mic_intr_restore(struct mic_device *mdev) 613 + { 614 + int entry, offset; 615 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 616 + struct pci_dev, dev); 617 + 618 + if (!pci_dev_msi_enabled(pdev)) 619 + return; 620 + 621 + for (entry = 0; entry < mdev->irq_info.num_vectors; entry++) { 622 + for (offset = 0; offset < MIC_NUM_OFFSETS; offset++) { 623 + if (mdev->irq_info.mic_msi_map[entry] & BIT(offset)) 624 + mdev->intr_ops->program_msi_to_src_map(mdev, 625 + entry, offset, true); 626 + } 627 + } 628 + }
+137
drivers/misc/mic/host/mic_intr.h
··· 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 + #ifndef _MIC_INTR_H_ 22 + #define _MIC_INTR_H_ 23 + 24 + /* 25 + * The minimum number of msix vectors required for normal operation. 26 + * 3 for virtio network, console and block devices. 27 + * 1 for card shutdown notifications. 28 + */ 29 + #define MIC_MIN_MSIX 4 30 + #define MIC_NUM_OFFSETS 32 31 + 32 + /** 33 + * mic_intr_source - The type of source that will generate 34 + * the interrupt.The number of types needs to be in sync with 35 + * MIC_NUM_INTR_TYPES 36 + * 37 + * MIC_INTR_DB: The source is a doorbell 38 + * MIC_INTR_DMA: The source is a DMA channel 39 + * MIC_INTR_ERR: The source is an error interrupt e.g. SBOX ERR 40 + * MIC_NUM_INTR_TYPES: Total number of interrupt sources. 41 + */ 42 + enum mic_intr_type { 43 + MIC_INTR_DB = 0, 44 + MIC_INTR_DMA, 45 + MIC_INTR_ERR, 46 + MIC_NUM_INTR_TYPES 47 + }; 48 + 49 + /** 50 + * struct mic_intr_info - Contains h/w specific interrupt sources 51 + * information. 52 + * 53 + * @intr_start_idx: Contains the starting indexes of the 54 + * interrupt types. 55 + * @intr_len: Contains the length of the interrupt types. 56 + */ 57 + struct mic_intr_info { 58 + u16 intr_start_idx[MIC_NUM_INTR_TYPES]; 59 + u16 intr_len[MIC_NUM_INTR_TYPES]; 60 + }; 61 + 62 + /** 63 + * struct mic_irq_info - OS specific irq information 64 + * 65 + * @next_avail_src: next available doorbell that can be assigned. 66 + * @msix_entries: msix entries allocated while setting up MSI-x 67 + * @mic_msi_map: The MSI/MSI-x mapping information. 68 + * @num_vectors: The number of MSI/MSI-x vectors that have been allocated. 69 + * @cb_ida: callback ID allocator to track the callbacks registered. 70 + * @mic_intr_lock: spinlock to protect the interrupt callback list. 71 + * @cb_list: Array of callback lists one for each source. 72 + */ 73 + struct mic_irq_info { 74 + int next_avail_src; 75 + struct msix_entry *msix_entries; 76 + u32 *mic_msi_map; 77 + u16 num_vectors; 78 + struct ida cb_ida; 79 + spinlock_t mic_intr_lock; 80 + struct list_head *cb_list; 81 + }; 82 + 83 + /** 84 + * struct mic_intr_cb - Interrupt callback structure. 85 + * 86 + * @func: The callback function 87 + * @data: Private data of the requester. 88 + * @cb_id: The callback id. Identifies this callback. 89 + * @list: list head pointing to the next callback structure. 90 + */ 91 + struct mic_intr_cb { 92 + irqreturn_t (*func) (int irq, void *data); 93 + void *data; 94 + int cb_id; 95 + struct list_head list; 96 + }; 97 + 98 + /** 99 + * struct mic_irq - opaque pointer used as cookie 100 + */ 101 + struct mic_irq; 102 + 103 + /* Forward declaration */ 104 + struct mic_device; 105 + 106 + /** 107 + * struct mic_hw_intr_ops: MIC HW specific interrupt operations 108 + * @intr_init: Initialize H/W specific interrupt information. 109 + * @enable_interrupts: Enable interrupts from the hardware. 110 + * @disable_interrupts: Disable interrupts from the hardware. 111 + * @program_msi_to_src_map: Update MSI mapping registers with 112 + * irq information. 113 + * @read_msi_to_src_map: Read MSI mapping registers containing 114 + * irq information. 115 + */ 116 + struct mic_hw_intr_ops { 117 + void (*intr_init)(struct mic_device *mdev); 118 + void (*enable_interrupts)(struct mic_device *mdev); 119 + void (*disable_interrupts)(struct mic_device *mdev); 120 + void (*program_msi_to_src_map) (struct mic_device *mdev, 121 + int idx, int intr_src, bool set); 122 + u32 (*read_msi_to_src_map) (struct mic_device *mdev, 123 + int idx); 124 + }; 125 + 126 + int mic_next_db(struct mic_device *mdev); 127 + struct mic_irq *mic_request_irq(struct mic_device *mdev, 128 + irqreturn_t (*func)(int irq, void *data), 129 + const char *name, void *data, int intr_src, 130 + enum mic_intr_type type); 131 + 132 + void mic_free_irq(struct mic_device *mdev, 133 + struct mic_irq *cookie, void *data); 134 + int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev); 135 + void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev); 136 + void mic_intr_restore(struct mic_device *mdev); 137 + #endif
+24 -2
drivers/misc/mic/host/mic_main.c
··· 23 23 * 2) Enable per vring interrupt support. 24 24 */ 25 25 #include <linux/fs.h> 26 - #include <linux/idr.h> 27 26 #include <linux/module.h> 28 27 #include <linux/pci.h> 29 28 30 29 #include "../common/mic_device.h" 31 30 #include "mic_device.h" 32 31 #include "mic_x100.h" 32 + #include "mic_smpt.h" 33 33 34 34 static const char mic_driver_name[] = "mic"; 35 35 ··· 75 75 switch (mdev->family) { 76 76 case MIC_FAMILY_X100: 77 77 mdev->ops = &mic_x100_ops; 78 + mdev->intr_ops = &mic_x100_intr_ops; 79 + mdev->smpt_ops = &mic_x100_smpt_ops; 78 80 break; 79 81 default: 80 82 break; ··· 134 132 mdev->stepping = pdev->revision; 135 133 mic_ops_init(mdev); 136 134 mic_sysfs_init(mdev); 135 + mutex_init(&mdev->mic_mutex); 136 + mdev->irq_info.next_avail_src = 0; 137 137 } 138 138 139 139 /** ··· 205 201 goto unmap_mmio; 206 202 } 207 203 204 + mdev->intr_ops->intr_init(mdev); 205 + rc = mic_setup_interrupts(mdev, pdev); 206 + if (rc) { 207 + dev_err(&pdev->dev, "mic_setup_interrupts failed %d\n", rc); 208 + goto unmap_aper; 209 + } 210 + rc = mic_smpt_init(mdev); 211 + if (rc) { 212 + dev_err(&pdev->dev, "smpt_init failed %d\n", rc); 213 + goto free_interrupts; 214 + } 215 + 208 216 pci_set_drvdata(pdev, mdev); 209 217 210 218 mdev->sdev = device_create_with_groups(g_mic_class, &pdev->dev, ··· 226 210 rc = PTR_ERR(mdev->sdev); 227 211 dev_err(&pdev->dev, 228 212 "device_create_with_groups failed rc %d\n", rc); 229 - goto unmap_aper; 213 + goto smpt_uninit; 230 214 } 231 215 return 0; 216 + smpt_uninit: 217 + mic_smpt_uninit(mdev); 218 + free_interrupts: 219 + mic_free_interrupts(mdev, pdev); 232 220 unmap_aper: 233 221 iounmap(mdev->aper.va); 234 222 unmap_mmio: ··· 266 246 return; 267 247 268 248 device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); 249 + mic_smpt_uninit(mdev); 250 + mic_free_interrupts(mdev, pdev); 269 251 iounmap(mdev->mmio.va); 270 252 iounmap(mdev->aper.va); 271 253 pci_release_regions(pdev);
+442
drivers/misc/mic/host/mic_smpt.c
··· 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/pci.h> 22 + 23 + #include "../common/mic_device.h" 24 + #include "mic_device.h" 25 + #include "mic_smpt.h" 26 + 27 + static inline u64 mic_system_page_mask(struct mic_device *mdev) 28 + { 29 + return (1ULL << mdev->smpt->info.page_shift) - 1ULL; 30 + } 31 + 32 + static inline u8 mic_sys_addr_to_smpt(struct mic_device *mdev, dma_addr_t pa) 33 + { 34 + return (pa - mdev->smpt->info.base) >> mdev->smpt->info.page_shift; 35 + } 36 + 37 + static inline u64 mic_smpt_to_pa(struct mic_device *mdev, u8 index) 38 + { 39 + return mdev->smpt->info.base + (index * mdev->smpt->info.page_size); 40 + } 41 + 42 + static inline u64 mic_smpt_offset(struct mic_device *mdev, dma_addr_t pa) 43 + { 44 + return pa & mic_system_page_mask(mdev); 45 + } 46 + 47 + static inline u64 mic_smpt_align_low(struct mic_device *mdev, dma_addr_t pa) 48 + { 49 + return ALIGN(pa - mic_system_page_mask(mdev), 50 + mdev->smpt->info.page_size); 51 + } 52 + 53 + static inline u64 mic_smpt_align_high(struct mic_device *mdev, dma_addr_t pa) 54 + { 55 + return ALIGN(pa, mdev->smpt->info.page_size); 56 + } 57 + 58 + /* Total Cumulative system memory accessible by MIC across all SMPT entries */ 59 + static inline u64 mic_max_system_memory(struct mic_device *mdev) 60 + { 61 + return mdev->smpt->info.num_reg * mdev->smpt->info.page_size; 62 + } 63 + 64 + /* Maximum system memory address accessible by MIC */ 65 + static inline u64 mic_max_system_addr(struct mic_device *mdev) 66 + { 67 + return mdev->smpt->info.base + mic_max_system_memory(mdev) - 1ULL; 68 + } 69 + 70 + /* Check if the DMA address is a MIC system memory address */ 71 + static inline bool 72 + mic_is_system_addr(struct mic_device *mdev, dma_addr_t pa) 73 + { 74 + return pa >= mdev->smpt->info.base && pa <= mic_max_system_addr(mdev); 75 + } 76 + 77 + /* Populate an SMPT entry and update the reference counts. */ 78 + static void mic_add_smpt_entry(int spt, s64 *ref, u64 addr, 79 + int entries, struct mic_device *mdev) 80 + { 81 + struct mic_smpt_info *smpt_info = mdev->smpt; 82 + int i; 83 + 84 + for (i = spt; i < spt + entries; i++, 85 + addr += smpt_info->info.page_size) { 86 + if (!smpt_info->entry[i].ref_count && 87 + (smpt_info->entry[i].dma_addr != addr)) { 88 + mdev->smpt_ops->set(mdev, addr, i); 89 + smpt_info->entry[i].dma_addr = addr; 90 + } 91 + smpt_info->entry[i].ref_count += ref[i - spt]; 92 + } 93 + } 94 + 95 + /* 96 + * Find an available MIC address in MIC SMPT address space 97 + * for a given DMA address and size. 98 + */ 99 + static dma_addr_t mic_smpt_op(struct mic_device *mdev, u64 dma_addr, 100 + int entries, s64 *ref, size_t size) 101 + { 102 + int spt; 103 + int ae = 0; 104 + int i; 105 + unsigned long flags; 106 + dma_addr_t mic_addr = 0; 107 + dma_addr_t addr = dma_addr; 108 + struct mic_smpt_info *smpt_info = mdev->smpt; 109 + 110 + spin_lock_irqsave(&smpt_info->smpt_lock, flags); 111 + 112 + /* find existing entries */ 113 + for (i = 0; i < smpt_info->info.num_reg; i++) { 114 + if (smpt_info->entry[i].dma_addr == addr) { 115 + ae++; 116 + addr += smpt_info->info.page_size; 117 + } else if (ae) /* cannot find contiguous entries */ 118 + goto not_found; 119 + 120 + if (ae == entries) 121 + goto found; 122 + } 123 + 124 + /* find free entry */ 125 + for (ae = 0, i = 0; i < smpt_info->info.num_reg; i++) { 126 + ae = (smpt_info->entry[i].ref_count == 0) ? ae + 1 : 0; 127 + if (ae == entries) 128 + goto found; 129 + } 130 + 131 + not_found: 132 + spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); 133 + return mic_addr; 134 + 135 + found: 136 + spt = i - entries + 1; 137 + mic_addr = mic_smpt_to_pa(mdev, spt); 138 + mic_add_smpt_entry(spt, ref, dma_addr, entries, mdev); 139 + smpt_info->map_count++; 140 + smpt_info->ref_count += (s64)size; 141 + spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); 142 + return mic_addr; 143 + } 144 + 145 + /* 146 + * Returns number of smpt entries needed for dma_addr to dma_addr + size 147 + * also returns the reference count array for each of those entries 148 + * and the starting smpt address 149 + */ 150 + static int mic_get_smpt_ref_count(struct mic_device *mdev, dma_addr_t dma_addr, 151 + size_t size, s64 *ref, u64 *smpt_start) 152 + { 153 + u64 start = dma_addr; 154 + u64 end = dma_addr + size; 155 + int i = 0; 156 + 157 + while (start < end) { 158 + ref[i++] = min(mic_smpt_align_high(mdev, start + 1), 159 + end) - start; 160 + start = mic_smpt_align_high(mdev, start + 1); 161 + } 162 + 163 + if (smpt_start) 164 + *smpt_start = mic_smpt_align_low(mdev, dma_addr); 165 + 166 + return i; 167 + } 168 + 169 + /* 170 + * mic_to_dma_addr - Converts a MIC address to a DMA address. 171 + * 172 + * @mdev: pointer to mic_device instance. 173 + * @mic_addr: MIC address. 174 + * 175 + * returns a DMA address. 176 + */ 177 + static dma_addr_t 178 + mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr) 179 + { 180 + struct mic_smpt_info *smpt_info = mdev->smpt; 181 + int spt; 182 + dma_addr_t dma_addr; 183 + 184 + if (!mic_is_system_addr(mdev, mic_addr)) { 185 + dev_err(mdev->sdev->parent, 186 + "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); 187 + return -EINVAL; 188 + } 189 + spt = mic_sys_addr_to_smpt(mdev, mic_addr); 190 + dma_addr = smpt_info->entry[spt].dma_addr + 191 + mic_smpt_offset(mdev, mic_addr); 192 + return dma_addr; 193 + } 194 + 195 + /** 196 + * mic_map - Maps a DMA address to a MIC physical address. 197 + * 198 + * @mdev: pointer to mic_device instance. 199 + * @dma_addr: DMA address. 200 + * @size: Size of the region to be mapped. 201 + * 202 + * This API converts the DMA address provided to a DMA address understood 203 + * by MIC. Caller should check for errors by calling mic_map_error(..). 204 + * 205 + * returns DMA address as required by MIC. 206 + */ 207 + dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size) 208 + { 209 + dma_addr_t mic_addr = 0; 210 + int num_entries; 211 + s64 *ref; 212 + u64 smpt_start; 213 + 214 + if (!size || size > mic_max_system_memory(mdev)) 215 + return mic_addr; 216 + 217 + ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL); 218 + if (!ref) 219 + return mic_addr; 220 + 221 + num_entries = mic_get_smpt_ref_count(mdev, dma_addr, size, 222 + ref, &smpt_start); 223 + 224 + /* Set the smpt table appropriately and get 16G aligned mic address */ 225 + mic_addr = mic_smpt_op(mdev, smpt_start, num_entries, ref, size); 226 + 227 + kfree(ref); 228 + 229 + /* 230 + * If mic_addr is zero then its an error case 231 + * since mic_addr can never be zero. 232 + * else generate mic_addr by adding the 16G offset in dma_addr 233 + */ 234 + if (!mic_addr && MIC_FAMILY_X100 == mdev->family) { 235 + dev_err(mdev->sdev->parent, 236 + "mic_map failed dma_addr 0x%llx size 0x%lx\n", 237 + dma_addr, size); 238 + return mic_addr; 239 + } else { 240 + return mic_addr + mic_smpt_offset(mdev, dma_addr); 241 + } 242 + } 243 + 244 + /** 245 + * mic_unmap - Unmaps a MIC physical address. 246 + * 247 + * @mdev: pointer to mic_device instance. 248 + * @mic_addr: MIC physical address. 249 + * @size: Size of the region to be unmapped. 250 + * 251 + * This API unmaps the mappings created by mic_map(..). 252 + * 253 + * returns None. 254 + */ 255 + void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) 256 + { 257 + struct mic_smpt_info *smpt_info = mdev->smpt; 258 + s64 *ref; 259 + int num_smpt; 260 + int spt; 261 + int i; 262 + unsigned long flags; 263 + 264 + if (!size) 265 + return; 266 + 267 + if (!mic_is_system_addr(mdev, mic_addr)) { 268 + dev_err(mdev->sdev->parent, 269 + "invalid address: 0x%llx\n", mic_addr); 270 + return; 271 + } 272 + 273 + spt = mic_sys_addr_to_smpt(mdev, mic_addr); 274 + ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL); 275 + if (!ref) 276 + return; 277 + 278 + /* Get number of smpt entries to be mapped, ref count array */ 279 + num_smpt = mic_get_smpt_ref_count(mdev, mic_addr, size, ref, NULL); 280 + 281 + spin_lock_irqsave(&smpt_info->smpt_lock, flags); 282 + smpt_info->unmap_count++; 283 + smpt_info->ref_count -= (s64)size; 284 + 285 + for (i = spt; i < spt + num_smpt; i++) { 286 + smpt_info->entry[i].ref_count -= ref[i - spt]; 287 + if (smpt_info->entry[i].ref_count < 0) 288 + dev_warn(mdev->sdev->parent, 289 + "ref count for entry %d is negative\n", i); 290 + } 291 + spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); 292 + kfree(ref); 293 + } 294 + 295 + /** 296 + * mic_map_single - Maps a virtual address to a MIC physical address. 297 + * 298 + * @mdev: pointer to mic_device instance. 299 + * @va: Kernel direct mapped virtual address. 300 + * @size: Size of the region to be mapped. 301 + * 302 + * This API calls pci_map_single(..) for the direct mapped virtual address 303 + * and then converts the DMA address provided to a DMA address understood 304 + * by MIC. Caller should check for errors by calling mic_map_error(..). 305 + * 306 + * returns DMA address as required by MIC. 307 + */ 308 + dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) 309 + { 310 + dma_addr_t mic_addr = 0; 311 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 312 + struct pci_dev, dev); 313 + dma_addr_t dma_addr = 314 + pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL); 315 + 316 + if (!pci_dma_mapping_error(pdev, dma_addr)) { 317 + mic_addr = mic_map(mdev, dma_addr, size); 318 + if (!mic_addr) { 319 + dev_err(mdev->sdev->parent, 320 + "mic_map failed dma_addr 0x%llx size 0x%lx\n", 321 + dma_addr, size); 322 + pci_unmap_single(pdev, dma_addr, 323 + size, PCI_DMA_BIDIRECTIONAL); 324 + } 325 + } 326 + return mic_addr; 327 + } 328 + 329 + /** 330 + * mic_unmap_single - Unmaps a MIC physical address. 331 + * 332 + * @mdev: pointer to mic_device instance. 333 + * @mic_addr: MIC physical address. 334 + * @size: Size of the region to be unmapped. 335 + * 336 + * This API unmaps the mappings created by mic_map_single(..). 337 + * 338 + * returns None. 339 + */ 340 + void 341 + mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) 342 + { 343 + struct pci_dev *pdev = container_of(mdev->sdev->parent, 344 + struct pci_dev, dev); 345 + dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr); 346 + mic_unmap(mdev, mic_addr, size); 347 + pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); 348 + } 349 + 350 + /** 351 + * mic_smpt_init - Initialize MIC System Memory Page Tables. 352 + * 353 + * @mdev: pointer to mic_device instance. 354 + * 355 + * returns 0 for success and -errno for error. 356 + */ 357 + int mic_smpt_init(struct mic_device *mdev) 358 + { 359 + int i, err = 0; 360 + dma_addr_t dma_addr; 361 + struct mic_smpt_info *smpt_info; 362 + 363 + mdev->smpt = kmalloc(sizeof(*mdev->smpt), GFP_KERNEL); 364 + if (!mdev->smpt) 365 + return -ENOMEM; 366 + 367 + smpt_info = mdev->smpt; 368 + mdev->smpt_ops->init(mdev); 369 + smpt_info->entry = kmalloc(sizeof(struct mic_smpt) 370 + * smpt_info->info.num_reg, GFP_KERNEL); 371 + if (!smpt_info->entry) { 372 + err = -ENOMEM; 373 + goto free_smpt; 374 + } 375 + spin_lock_init(&smpt_info->smpt_lock); 376 + for (i = 0; i < smpt_info->info.num_reg; i++) { 377 + dma_addr = i * smpt_info->info.page_size; 378 + smpt_info->entry[i].dma_addr = dma_addr; 379 + smpt_info->entry[i].ref_count = 0; 380 + mdev->smpt_ops->set(mdev, dma_addr, i); 381 + } 382 + smpt_info->ref_count = 0; 383 + smpt_info->map_count = 0; 384 + smpt_info->unmap_count = 0; 385 + return 0; 386 + free_smpt: 387 + kfree(smpt_info); 388 + return err; 389 + } 390 + 391 + /** 392 + * mic_smpt_uninit - UnInitialize MIC System Memory Page Tables. 393 + * 394 + * @mdev: pointer to mic_device instance. 395 + * 396 + * returns None. 397 + */ 398 + void mic_smpt_uninit(struct mic_device *mdev) 399 + { 400 + struct mic_smpt_info *smpt_info = mdev->smpt; 401 + int i; 402 + 403 + dev_dbg(mdev->sdev->parent, 404 + "nodeid %d SMPT ref count %lld map %lld unmap %lld\n", 405 + mdev->id, smpt_info->ref_count, 406 + smpt_info->map_count, smpt_info->unmap_count); 407 + 408 + for (i = 0; i < smpt_info->info.num_reg; i++) { 409 + dev_dbg(mdev->sdev->parent, 410 + "SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n", 411 + i, smpt_info->entry[i].dma_addr, 412 + smpt_info->entry[i].ref_count); 413 + if (smpt_info->entry[i].ref_count) 414 + dev_warn(mdev->sdev->parent, 415 + "ref count for entry %d is not zero\n", i); 416 + } 417 + kfree(smpt_info->entry); 418 + kfree(smpt_info); 419 + } 420 + 421 + /** 422 + * mic_smpt_restore - Restore MIC System Memory Page Tables. 423 + * 424 + * @mdev: pointer to mic_device instance. 425 + * 426 + * Restore the SMPT registers to values previously stored in the 427 + * SW data structures. Some MIC steppings lose register state 428 + * across resets and this API should be called for performing 429 + * a restore operation if required. 430 + * 431 + * returns None. 432 + */ 433 + void mic_smpt_restore(struct mic_device *mdev) 434 + { 435 + int i; 436 + dma_addr_t dma_addr; 437 + 438 + for (i = 0; i < mdev->smpt->info.num_reg; i++) { 439 + dma_addr = mdev->smpt->entry[i].dma_addr; 440 + mdev->smpt_ops->set(mdev, dma_addr, i); 441 + } 442 + }
+98
drivers/misc/mic/host/mic_smpt.h
··· 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 + #ifndef MIC_SMPT_H 22 + #define MIC_SMPT_H 23 + /** 24 + * struct mic_smpt_ops - MIC HW specific SMPT operations. 25 + * @init: Initialize hardware specific SMPT information in mic_smpt_hw_info. 26 + * @set: Set the value for a particular SMPT entry. 27 + */ 28 + struct mic_smpt_ops { 29 + void (*init)(struct mic_device *mdev); 30 + void (*set)(struct mic_device *mdev, dma_addr_t dma_addr, u8 index); 31 + }; 32 + 33 + /** 34 + * struct mic_smpt - MIC SMPT entry information. 35 + * @dma_addr: Base DMA address for this SMPT entry. 36 + * @ref_count: Number of active mappings for this SMPT entry in bytes. 37 + */ 38 + struct mic_smpt { 39 + dma_addr_t dma_addr; 40 + s64 ref_count; 41 + }; 42 + 43 + /** 44 + * struct mic_smpt_hw_info - MIC SMPT hardware specific information. 45 + * @num_reg: Number of SMPT registers. 46 + * @page_shift: System memory page shift. 47 + * @page_size: System memory page size. 48 + * @base: System address base. 49 + */ 50 + struct mic_smpt_hw_info { 51 + u8 num_reg; 52 + u8 page_shift; 53 + u64 page_size; 54 + u64 base; 55 + }; 56 + 57 + /** 58 + * struct mic_smpt_info - MIC SMPT information. 59 + * @entry: Array of SMPT entries. 60 + * @smpt_lock: Spin lock protecting access to SMPT data structures. 61 + * @info: Hardware specific SMPT information. 62 + * @ref_count: Number of active SMPT mappings (for debug). 63 + * @map_count: Number of SMPT mappings created (for debug). 64 + * @unmap_count: Number of SMPT mappings destroyed (for debug). 65 + */ 66 + struct mic_smpt_info { 67 + struct mic_smpt *entry; 68 + spinlock_t smpt_lock; 69 + struct mic_smpt_hw_info info; 70 + s64 ref_count; 71 + s64 map_count; 72 + s64 unmap_count; 73 + }; 74 + 75 + dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size); 76 + void mic_unmap_single(struct mic_device *mdev, 77 + dma_addr_t mic_addr, size_t size); 78 + dma_addr_t mic_map(struct mic_device *mdev, 79 + dma_addr_t dma_addr, size_t size); 80 + void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size); 81 + 82 + /** 83 + * mic_map_error - Check a MIC address for errors. 84 + * 85 + * @mdev: pointer to mic_device instance. 86 + * 87 + * returns Whether there was an error during mic_map..(..) APIs. 88 + */ 89 + static inline bool mic_map_error(dma_addr_t mic_addr) 90 + { 91 + return !mic_addr; 92 + } 93 + 94 + int mic_smpt_init(struct mic_device *mdev); 95 + void mic_smpt_uninit(struct mic_device *mdev); 96 + void mic_smpt_restore(struct mic_device *mdev); 97 + 98 + #endif
+247
drivers/misc/mic/host/mic_x100.c
··· 24 24 #include "../common/mic_device.h" 25 25 #include "mic_device.h" 26 26 #include "mic_x100.h" 27 + #include "mic_smpt.h" 27 28 28 29 /** 29 30 * mic_x100_write_spad - write to the scratchpad register ··· 68 67 return val; 69 68 } 70 69 70 + /** 71 + * mic_x100_enable_interrupts - Enable interrupts. 72 + * @mdev: pointer to mic_device instance 73 + */ 74 + static void mic_x100_enable_interrupts(struct mic_device *mdev) 75 + { 76 + u32 reg; 77 + struct mic_mw *mw = &mdev->mmio; 78 + u32 sice0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICE0; 79 + u32 siac0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SIAC0; 80 + 81 + reg = mic_mmio_read(mw, sice0); 82 + reg |= MIC_X100_SBOX_DBR_BITS(0xf) | MIC_X100_SBOX_DMA_BITS(0xff); 83 + mic_mmio_write(mw, reg, sice0); 84 + 85 + /* 86 + * Enable auto-clear when enabling interrupts. Applicable only for 87 + * MSI-x. Legacy and MSI mode cannot have auto-clear enabled. 88 + */ 89 + if (mdev->irq_info.num_vectors > 1) { 90 + reg = mic_mmio_read(mw, siac0); 91 + reg |= MIC_X100_SBOX_DBR_BITS(0xf) | 92 + MIC_X100_SBOX_DMA_BITS(0xff); 93 + mic_mmio_write(mw, reg, siac0); 94 + } 95 + } 96 + 97 + /** 98 + * mic_x100_disable_interrupts - Disable interrupts. 99 + * @mdev: pointer to mic_device instance 100 + */ 101 + static void mic_x100_disable_interrupts(struct mic_device *mdev) 102 + { 103 + u32 reg; 104 + struct mic_mw *mw = &mdev->mmio; 105 + u32 sice0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICE0; 106 + u32 siac0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SIAC0; 107 + u32 sicc0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICC0; 108 + 109 + reg = mic_mmio_read(mw, sice0); 110 + mic_mmio_write(mw, reg, sicc0); 111 + 112 + if (mdev->irq_info.num_vectors > 1) { 113 + reg = mic_mmio_read(mw, siac0); 114 + reg &= ~(MIC_X100_SBOX_DBR_BITS(0xf) | 115 + MIC_X100_SBOX_DMA_BITS(0xff)); 116 + mic_mmio_write(mw, reg, siac0); 117 + } 118 + } 119 + 120 + /** 121 + * mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC. 122 + * @mdev: pointer to mic_device instance 123 + */ 124 + static void mic_x100_send_sbox_intr(struct mic_device *mdev, 125 + int doorbell) 126 + { 127 + struct mic_mw *mw = &mdev->mmio; 128 + u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8; 129 + u32 apicicr_low = mic_mmio_read(mw, 130 + MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); 131 + 132 + /* for MIC we need to make sure we "hit" the send_icr bit (13) */ 133 + apicicr_low = (apicicr_low | (1 << 13)); 134 + 135 + /* Ensure that the interrupt is ordered w.r.t. previous stores. */ 136 + wmb(); 137 + mic_mmio_write(mw, apicicr_low, 138 + MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); 139 + } 140 + 141 + /** 142 + * mic_x100_send_rdmasr_intr - Send an RDMASR interrupt to MIC. 143 + * @mdev: pointer to mic_device instance 144 + */ 145 + static void mic_x100_send_rdmasr_intr(struct mic_device *mdev, 146 + int doorbell) 147 + { 148 + int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2); 149 + /* Ensure that the interrupt is ordered w.r.t. previous stores. */ 150 + wmb(); 151 + mic_mmio_write(&mdev->mmio, 0, 152 + MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset); 153 + } 154 + 155 + /** 156 + * __mic_x100_send_intr - Send interrupt to MIC. 157 + * @mdev: pointer to mic_device instance 158 + * @doorbell: doorbell number. 159 + */ 160 + static void mic_x100_send_intr(struct mic_device *mdev, int doorbell) 161 + { 162 + int rdmasr_db; 163 + if (doorbell < MIC_X100_NUM_SBOX_IRQ) { 164 + mic_x100_send_sbox_intr(mdev, doorbell); 165 + } else { 166 + rdmasr_db = doorbell - MIC_X100_NUM_SBOX_IRQ + 167 + MIC_X100_RDMASR_IRQ_BASE; 168 + mic_x100_send_rdmasr_intr(mdev, rdmasr_db); 169 + } 170 + } 171 + 172 + /** 173 + * mic_ack_interrupt - Device specific interrupt handling. 174 + * @mdev: pointer to mic_device instance 175 + * 176 + * Returns: bitmask of doorbell events triggered. 177 + */ 178 + static u32 mic_x100_ack_interrupt(struct mic_device *mdev) 179 + { 180 + u32 reg = 0; 181 + struct mic_mw *mw = &mdev->mmio; 182 + u32 sicr0 = MIC_X100_SBOX_BASE_ADDRESS + MIC_X100_SBOX_SICR0; 183 + 184 + /* Clear pending bit array. */ 185 + if (MIC_A0_STEP == mdev->stepping) 186 + mic_mmio_write(mw, 1, MIC_X100_SBOX_BASE_ADDRESS + 187 + MIC_X100_SBOX_MSIXPBACR); 188 + 189 + if (mdev->irq_info.num_vectors <= 1) { 190 + reg = mic_mmio_read(mw, sicr0); 191 + 192 + if (unlikely(!reg)) 193 + goto done; 194 + 195 + mic_mmio_write(mw, reg, sicr0); 196 + } 197 + 198 + if (mdev->stepping >= MIC_B0_STEP) 199 + mdev->intr_ops->enable_interrupts(mdev); 200 + done: 201 + return reg; 202 + } 203 + 204 + /** 205 + * mic_x100_hw_intr_init - Initialize h/w specific interrupt 206 + * information. 207 + * @mdev: pointer to mic_device instance 208 + */ 209 + static void mic_x100_hw_intr_init(struct mic_device *mdev) 210 + { 211 + mdev->intr_info = (struct mic_intr_info *) mic_x100_intr_init; 212 + } 213 + 214 + /** 215 + * mic_x100_read_msi_to_src_map - read from the MSI mapping registers 216 + * @mdev: pointer to mic_device instance 217 + * @idx: index to the mapping register, 0 based 218 + * 219 + * This function allows reading of the 32bit MSI mapping register. 220 + * 221 + * RETURNS: The value in the register. 222 + */ 223 + static u32 224 + mic_x100_read_msi_to_src_map(struct mic_device *mdev, int idx) 225 + { 226 + return mic_mmio_read(&mdev->mmio, 227 + MIC_X100_SBOX_BASE_ADDRESS + 228 + MIC_X100_SBOX_MXAR0 + idx * 4); 229 + } 230 + 231 + /** 232 + * mic_x100_program_msi_to_src_map - program the MSI mapping registers 233 + * @mdev: pointer to mic_device instance 234 + * @idx: index to the mapping register, 0 based 235 + * @offset: The bit offset in the register that needs to be updated. 236 + * @set: boolean specifying if the bit in the specified offset needs 237 + * to be set or cleared. 238 + * 239 + * RETURNS: None. 240 + */ 241 + static void 242 + mic_x100_program_msi_to_src_map(struct mic_device *mdev, 243 + int idx, int offset, bool set) 244 + { 245 + unsigned long reg; 246 + struct mic_mw *mw = &mdev->mmio; 247 + u32 mxar = MIC_X100_SBOX_BASE_ADDRESS + 248 + MIC_X100_SBOX_MXAR0 + idx * 4; 249 + 250 + reg = mic_mmio_read(mw, mxar); 251 + if (set) 252 + __set_bit(offset, &reg); 253 + else 254 + __clear_bit(offset, &reg); 255 + mic_mmio_write(mw, reg, mxar); 256 + } 257 + 258 + /** 259 + * mic_x100_smpt_set - Update an SMPT entry with a DMA address. 260 + * @mdev: pointer to mic_device instance 261 + * 262 + * RETURNS: none. 263 + */ 264 + static void 265 + mic_x100_smpt_set(struct mic_device *mdev, dma_addr_t dma_addr, u8 index) 266 + { 267 + #define SNOOP_ON (0 << 0) 268 + #define SNOOP_OFF (1 << 0) 269 + /* 270 + * Sbox Smpt Reg Bits: 271 + * Bits 31:2 Host address 272 + * Bits 1 RSVD 273 + * Bits 0 No snoop 274 + */ 275 + #define BUILD_SMPT(NO_SNOOP, HOST_ADDR) \ 276 + (u32)(((HOST_ADDR) << 2) | ((NO_SNOOP) & 0x01)) 277 + 278 + uint32_t smpt_reg_val = BUILD_SMPT(SNOOP_ON, 279 + dma_addr >> mdev->smpt->info.page_shift); 280 + mic_mmio_write(&mdev->mmio, smpt_reg_val, 281 + MIC_X100_SBOX_BASE_ADDRESS + 282 + MIC_X100_SBOX_SMPT00 + (4 * index)); 283 + } 284 + 285 + /** 286 + * mic_x100_smpt_hw_init - Initialize SMPT X100 specific fields. 287 + * @mdev: pointer to mic_device instance 288 + * 289 + * RETURNS: none. 290 + */ 291 + static void mic_x100_smpt_hw_init(struct mic_device *mdev) 292 + { 293 + struct mic_smpt_hw_info *info = &mdev->smpt->info; 294 + 295 + info->num_reg = 32; 296 + info->page_shift = 34; 297 + info->page_size = (1ULL << info->page_shift); 298 + info->base = 0x8000000000ULL; 299 + } 300 + 301 + struct mic_smpt_ops mic_x100_smpt_ops = { 302 + .init = mic_x100_smpt_hw_init, 303 + .set = mic_x100_smpt_set, 304 + }; 305 + 71 306 struct mic_hw_ops mic_x100_ops = { 72 307 .aper_bar = MIC_X100_APER_BAR, 73 308 .mmio_bar = MIC_X100_MMIO_BAR, 74 309 .read_spad = mic_x100_read_spad, 75 310 .write_spad = mic_x100_write_spad, 311 + .send_intr = mic_x100_send_intr, 312 + .ack_interrupt = mic_x100_ack_interrupt, 313 + }; 314 + 315 + struct mic_hw_intr_ops mic_x100_intr_ops = { 316 + .intr_init = mic_x100_hw_intr_init, 317 + .enable_interrupts = mic_x100_enable_interrupts, 318 + .disable_interrupts = mic_x100_disable_interrupts, 319 + .program_msi_to_src_map = mic_x100_program_msi_to_src_map, 320 + .read_msi_to_src_map = mic_x100_read_msi_to_src_map, 76 321 };
+39
drivers/misc/mic/host/mic_x100.h
··· 42 42 43 43 #define MIC_X100_SBOX_BASE_ADDRESS 0x00010000 44 44 #define MIC_X100_SBOX_SPAD0 0x0000AB20 45 + #define MIC_X100_SBOX_SICR0_DBR(x) ((x) & 0xf) 46 + #define MIC_X100_SBOX_SICR0_DMA(x) (((x) >> 8) & 0xff) 47 + #define MIC_X100_SBOX_SICE0_DBR(x) ((x) & 0xf) 48 + #define MIC_X100_SBOX_DBR_BITS(x) ((x) & 0xf) 49 + #define MIC_X100_SBOX_SICE0_DMA(x) (((x) >> 8) & 0xff) 50 + #define MIC_X100_SBOX_DMA_BITS(x) (((x) & 0xff) << 8) 51 + 52 + #define MIC_X100_SBOX_APICICR0 0x0000A9D0 53 + #define MIC_X100_SBOX_SICR0 0x00009004 54 + #define MIC_X100_SBOX_SICE0 0x0000900C 55 + #define MIC_X100_SBOX_SICC0 0x00009010 56 + #define MIC_X100_SBOX_SIAC0 0x00009014 57 + #define MIC_X100_SBOX_MSIXPBACR 0x00009084 58 + #define MIC_X100_SBOX_MXAR0 0x00009044 59 + #define MIC_X100_SBOX_SMPT00 0x00003100 60 + #define MIC_X100_SBOX_RDMASR0 0x0000B180 61 + 62 + #define MIC_X100_DOORBELL_IDX_START 0 63 + #define MIC_X100_NUM_DOORBELL 4 64 + #define MIC_X100_DMA_IDX_START 8 65 + #define MIC_X100_NUM_DMA 8 66 + #define MIC_X100_ERR_IDX_START 30 67 + #define MIC_X100_NUM_ERR 1 68 + 69 + #define MIC_X100_NUM_SBOX_IRQ 8 70 + #define MIC_X100_NUM_RDMASR_IRQ 8 71 + #define MIC_X100_RDMASR_IRQ_BASE 17 72 + 73 + static const u16 mic_x100_intr_init[] = { 74 + MIC_X100_DOORBELL_IDX_START, 75 + MIC_X100_DMA_IDX_START, 76 + MIC_X100_ERR_IDX_START, 77 + MIC_X100_NUM_DOORBELL, 78 + MIC_X100_NUM_DMA, 79 + MIC_X100_NUM_ERR, 80 + }; 81 + 45 82 extern struct mic_hw_ops mic_x100_ops; 83 + extern struct mic_smpt_ops mic_x100_smpt_ops; 84 + extern struct mic_hw_intr_ops mic_x100_intr_ops; 46 85 47 86 #endif