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

Configure Feed

Select the types of activity you want to include in your feed.

at v5.3-rc2 351 lines 9.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel MIC Platform Software Stack (MPSS) 4 * 5 * Copyright(c) 2013 Intel Corporation. 6 * 7 * Disclaimer: The codes contained in these modules may be specific to 8 * the Intel Software Development Platform codenamed: Knights Ferry, and 9 * the Intel product codenamed: Knights Corner, and are not backward 10 * compatible with other Intel products. Additionally, Intel will NOT 11 * support the codes or instruction set in future products. 12 * 13 * Intel MIC Card driver. 14 */ 15#include <linux/module.h> 16#include <linux/pci.h> 17#include <linux/platform_device.h> 18 19#include "../common/mic_dev.h" 20#include "mic_device.h" 21#include "mic_x100.h" 22 23static const char mic_driver_name[] = "mic"; 24 25static struct mic_driver g_drv; 26 27/** 28 * mic_read_spad - read from the scratchpad register 29 * @mdev: pointer to mic_device instance 30 * @idx: index to scratchpad register, 0 based 31 * 32 * This function allows reading of the 32bit scratchpad register. 33 * 34 * RETURNS: An appropriate -ERRNO error value on error, or zero for success. 35 */ 36u32 mic_read_spad(struct mic_device *mdev, unsigned int idx) 37{ 38 return mic_mmio_read(&mdev->mmio, 39 MIC_X100_SBOX_BASE_ADDRESS + 40 MIC_X100_SBOX_SPAD0 + idx * 4); 41} 42 43/** 44 * __mic_send_intr - Send interrupt to Host. 45 * @mdev: pointer to mic_device instance 46 * @doorbell: Doorbell number. 47 */ 48void mic_send_intr(struct mic_device *mdev, int doorbell) 49{ 50 struct mic_mw *mw = &mdev->mmio; 51 52 if (doorbell > MIC_X100_MAX_DOORBELL_IDX) 53 return; 54 /* Ensure that the interrupt is ordered w.r.t previous stores. */ 55 wmb(); 56 mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT, 57 MIC_X100_SBOX_BASE_ADDRESS + 58 (MIC_X100_SBOX_SDBIC0 + (4 * doorbell))); 59} 60 61/* 62 * mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC. 63 */ 64static void mic_x100_send_sbox_intr(struct mic_mw *mw, int doorbell) 65{ 66 u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8; 67 u32 apicicr_low = mic_mmio_read(mw, MIC_X100_SBOX_BASE_ADDRESS + 68 apic_icr_offset); 69 70 /* for MIC we need to make sure we "hit" the send_icr bit (13) */ 71 apicicr_low = (apicicr_low | (1 << 13)); 72 /* 73 * Ensure that the interrupt is ordered w.r.t. previous stores 74 * to main memory. Fence instructions are not implemented in X100 75 * since execution is in order but a compiler barrier is still 76 * required. 77 */ 78 wmb(); 79 mic_mmio_write(mw, apicicr_low, 80 MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset); 81} 82 83static void mic_x100_send_rdmasr_intr(struct mic_mw *mw, int doorbell) 84{ 85 int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2); 86 /* 87 * Ensure that the interrupt is ordered w.r.t. previous stores 88 * to main memory. Fence instructions are not implemented in X100 89 * since execution is in order but a compiler barrier is still 90 * required. 91 */ 92 wmb(); 93 mic_mmio_write(mw, 0, MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset); 94} 95 96/** 97 * mic_ack_interrupt - Device specific interrupt handling. 98 * @mdev: pointer to mic_device instance 99 * 100 * Returns: bitmask of doorbell events triggered. 101 */ 102u32 mic_ack_interrupt(struct mic_device *mdev) 103{ 104 return 0; 105} 106 107static inline int mic_get_sbox_irq(int db) 108{ 109 return MIC_X100_IRQ_BASE + db; 110} 111 112static inline int mic_get_rdmasr_irq(int index) 113{ 114 return MIC_X100_RDMASR_IRQ_BASE + index; 115} 116 117void mic_send_p2p_intr(int db, struct mic_mw *mw) 118{ 119 int rdmasr_index; 120 121 if (db < MIC_X100_NUM_SBOX_IRQ) { 122 mic_x100_send_sbox_intr(mw, db); 123 } else { 124 rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ; 125 mic_x100_send_rdmasr_intr(mw, rdmasr_index); 126 } 127} 128 129/** 130 * mic_hw_intr_init - Initialize h/w specific interrupt 131 * information. 132 * @mdrv: pointer to mic_driver 133 */ 134void mic_hw_intr_init(struct mic_driver *mdrv) 135{ 136 mdrv->intr_info.num_intr = MIC_X100_NUM_SBOX_IRQ + 137 MIC_X100_NUM_RDMASR_IRQ; 138} 139 140/** 141 * mic_db_to_irq - Retrieve irq number corresponding to a doorbell. 142 * @mdrv: pointer to mic_driver 143 * @db: The doorbell obtained for which the irq is needed. Doorbell 144 * may correspond to an sbox doorbell or an rdmasr index. 145 * 146 * Returns the irq corresponding to the doorbell. 147 */ 148int mic_db_to_irq(struct mic_driver *mdrv, int db) 149{ 150 int rdmasr_index; 151 152 /* 153 * The total number of doorbell interrupts on the card are 16. Indices 154 * 0-8 falls in the SBOX category and 8-15 fall in the RDMASR category. 155 */ 156 if (db < MIC_X100_NUM_SBOX_IRQ) { 157 return mic_get_sbox_irq(db); 158 } else { 159 rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ; 160 return mic_get_rdmasr_irq(rdmasr_index); 161 } 162} 163 164/* 165 * mic_card_map - Allocate virtual address for a remote memory region. 166 * @mdev: pointer to mic_device instance. 167 * @addr: Remote DMA address. 168 * @size: Size of the region. 169 * 170 * Returns: Virtual address backing the remote memory region. 171 */ 172void __iomem * 173mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size) 174{ 175 return ioremap(addr, size); 176} 177 178/* 179 * mic_card_unmap - Unmap the virtual address for a remote memory region. 180 * @mdev: pointer to mic_device instance. 181 * @addr: Virtual address for remote memory region. 182 * 183 * Returns: None. 184 */ 185void mic_card_unmap(struct mic_device *mdev, void __iomem *addr) 186{ 187 iounmap(addr); 188} 189 190static inline struct mic_driver *mbdev_to_mdrv(struct mbus_device *mbdev) 191{ 192 return dev_get_drvdata(mbdev->dev.parent); 193} 194 195static struct mic_irq * 196_mic_request_threaded_irq(struct mbus_device *mbdev, 197 irq_handler_t handler, irq_handler_t thread_fn, 198 const char *name, void *data, int intr_src) 199{ 200 int rc = 0; 201 unsigned int irq = intr_src; 202 unsigned long cookie = irq; 203 204 rc = request_threaded_irq(irq, handler, thread_fn, 0, name, data); 205 if (rc) { 206 dev_err(mbdev_to_mdrv(mbdev)->dev, 207 "request_threaded_irq failed rc = %d\n", rc); 208 return ERR_PTR(rc); 209 } 210 return (struct mic_irq *)cookie; 211} 212 213static void _mic_free_irq(struct mbus_device *mbdev, 214 struct mic_irq *cookie, void *data) 215{ 216 unsigned long irq = (unsigned long)cookie; 217 free_irq(irq, data); 218} 219 220static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) 221{ 222 mic_ack_interrupt(&mbdev_to_mdrv(mbdev)->mdev); 223} 224 225static struct mbus_hw_ops mbus_hw_ops = { 226 .request_threaded_irq = _mic_request_threaded_irq, 227 .free_irq = _mic_free_irq, 228 .ack_interrupt = _mic_ack_interrupt, 229}; 230 231static int __init mic_probe(struct platform_device *pdev) 232{ 233 struct mic_driver *mdrv = &g_drv; 234 struct mic_device *mdev = &mdrv->mdev; 235 int rc = 0; 236 237 mdrv->dev = &pdev->dev; 238 snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name); 239 240 mdev->mmio.pa = MIC_X100_MMIO_BASE; 241 mdev->mmio.len = MIC_X100_MMIO_LEN; 242 mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE, 243 MIC_X100_MMIO_LEN); 244 if (!mdev->mmio.va) { 245 dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); 246 rc = -EIO; 247 goto done; 248 } 249 mic_hw_intr_init(mdrv); 250 platform_set_drvdata(pdev, mdrv); 251 mdrv->dma_mbdev = mbus_register_device(mdrv->dev, MBUS_DEV_DMA_MIC, 252 NULL, &mbus_hw_ops, 0, 253 mdrv->mdev.mmio.va); 254 if (IS_ERR(mdrv->dma_mbdev)) { 255 rc = PTR_ERR(mdrv->dma_mbdev); 256 dev_err(&pdev->dev, "mbus_add_device failed rc %d\n", rc); 257 goto done; 258 } 259 rc = mic_driver_init(mdrv); 260 if (rc) { 261 dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc); 262 goto remove_dma; 263 } 264done: 265 return rc; 266remove_dma: 267 mbus_unregister_device(mdrv->dma_mbdev); 268 return rc; 269} 270 271static int mic_remove(struct platform_device *pdev) 272{ 273 struct mic_driver *mdrv = &g_drv; 274 275 mic_driver_uninit(mdrv); 276 mbus_unregister_device(mdrv->dma_mbdev); 277 return 0; 278} 279 280static void mic_platform_shutdown(struct platform_device *pdev) 281{ 282 mic_remove(pdev); 283} 284 285static u64 mic_dma_mask = DMA_BIT_MASK(64); 286 287static struct platform_device mic_platform_dev = { 288 .name = mic_driver_name, 289 .id = 0, 290 .num_resources = 0, 291 .dev = { 292 .dma_mask = &mic_dma_mask, 293 .coherent_dma_mask = DMA_BIT_MASK(64), 294 }, 295}; 296 297static struct platform_driver __refdata mic_platform_driver = { 298 .probe = mic_probe, 299 .remove = mic_remove, 300 .shutdown = mic_platform_shutdown, 301 .driver = { 302 .name = mic_driver_name, 303 }, 304}; 305 306static int __init mic_init(void) 307{ 308 int ret; 309 struct cpuinfo_x86 *c = &cpu_data(0); 310 311 if (!(c->x86 == 11 && c->x86_model == 1)) { 312 ret = -ENODEV; 313 pr_err("%s not running on X100 ret %d\n", __func__, ret); 314 goto done; 315 } 316 317 request_module("mic_x100_dma"); 318 mic_init_card_debugfs(); 319 ret = platform_device_register(&mic_platform_dev); 320 if (ret) { 321 pr_err("platform_device_register ret %d\n", ret); 322 goto cleanup_debugfs; 323 } 324 ret = platform_driver_register(&mic_platform_driver); 325 if (ret) { 326 pr_err("platform_driver_register ret %d\n", ret); 327 goto device_unregister; 328 } 329 return ret; 330 331device_unregister: 332 platform_device_unregister(&mic_platform_dev); 333cleanup_debugfs: 334 mic_exit_card_debugfs(); 335done: 336 return ret; 337} 338 339static void __exit mic_exit(void) 340{ 341 platform_driver_unregister(&mic_platform_driver); 342 platform_device_unregister(&mic_platform_dev); 343 mic_exit_card_debugfs(); 344} 345 346module_init(mic_init); 347module_exit(mic_exit); 348 349MODULE_AUTHOR("Intel Corporation"); 350MODULE_DESCRIPTION("Intel(R) MIC X100 Card driver"); 351MODULE_LICENSE("GPL v2");