1*795536acSTomas Winkler /* 2*795536acSTomas Winkler * 3*795536acSTomas Winkler * Intel Management Engine Interface (Intel MEI) Linux driver 4*795536acSTomas Winkler * Copyright (c) 2013-2014, Intel Corporation. 5*795536acSTomas Winkler * 6*795536acSTomas Winkler * This program is free software; you can redistribute it and/or modify it 7*795536acSTomas Winkler * under the terms and conditions of the GNU General Public License, 8*795536acSTomas Winkler * version 2, as published by the Free Software Foundation. 9*795536acSTomas Winkler * 10*795536acSTomas Winkler * This program is distributed in the hope it will be useful, but WITHOUT 11*795536acSTomas Winkler * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12*795536acSTomas Winkler * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13*795536acSTomas Winkler * more details. 14*795536acSTomas Winkler * 15*795536acSTomas Winkler */ 16*795536acSTomas Winkler 17*795536acSTomas Winkler #include <linux/module.h> 18*795536acSTomas Winkler #include <linux/kernel.h> 19*795536acSTomas Winkler #include <linux/device.h> 20*795536acSTomas Winkler #include <linux/fs.h> 21*795536acSTomas Winkler #include <linux/errno.h> 22*795536acSTomas Winkler #include <linux/types.h> 23*795536acSTomas Winkler #include <linux/pci.h> 24*795536acSTomas Winkler #include <linux/init.h> 25*795536acSTomas Winkler #include <linux/sched.h> 26*795536acSTomas Winkler #include <linux/uuid.h> 27*795536acSTomas Winkler #include <linux/jiffies.h> 28*795536acSTomas Winkler #include <linux/interrupt.h> 29*795536acSTomas Winkler #include <linux/workqueue.h> 30*795536acSTomas Winkler 31*795536acSTomas Winkler #include <linux/mei.h> 32*795536acSTomas Winkler 33*795536acSTomas Winkler 34*795536acSTomas Winkler #include "mei_dev.h" 35*795536acSTomas Winkler #include "hw-txe.h" 36*795536acSTomas Winkler 37*795536acSTomas Winkler static DEFINE_PCI_DEVICE_TABLE(mei_txe_pci_tbl) = { 38*795536acSTomas Winkler {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */ 39*795536acSTomas Winkler {0, } 40*795536acSTomas Winkler }; 41*795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); 42*795536acSTomas Winkler 43*795536acSTomas Winkler 44*795536acSTomas Winkler static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) 45*795536acSTomas Winkler { 46*795536acSTomas Winkler int i; 47*795536acSTomas Winkler for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { 48*795536acSTomas Winkler if (hw->mem_addr[i]) { 49*795536acSTomas Winkler pci_iounmap(pdev, hw->mem_addr[i]); 50*795536acSTomas Winkler hw->mem_addr[i] = NULL; 51*795536acSTomas Winkler } 52*795536acSTomas Winkler } 53*795536acSTomas Winkler } 54*795536acSTomas Winkler /** 55*795536acSTomas Winkler * mei_probe - Device Initialization Routine 56*795536acSTomas Winkler * 57*795536acSTomas Winkler * @pdev: PCI device structure 58*795536acSTomas Winkler * @ent: entry in mei_txe_pci_tbl 59*795536acSTomas Winkler * 60*795536acSTomas Winkler * returns 0 on success, <0 on failure. 61*795536acSTomas Winkler */ 62*795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 63*795536acSTomas Winkler { 64*795536acSTomas Winkler struct mei_device *dev; 65*795536acSTomas Winkler struct mei_txe_hw *hw; 66*795536acSTomas Winkler int err; 67*795536acSTomas Winkler int i; 68*795536acSTomas Winkler 69*795536acSTomas Winkler /* enable pci dev */ 70*795536acSTomas Winkler err = pci_enable_device(pdev); 71*795536acSTomas Winkler if (err) { 72*795536acSTomas Winkler dev_err(&pdev->dev, "failed to enable pci device.\n"); 73*795536acSTomas Winkler goto end; 74*795536acSTomas Winkler } 75*795536acSTomas Winkler /* set PCI host mastering */ 76*795536acSTomas Winkler pci_set_master(pdev); 77*795536acSTomas Winkler /* pci request regions for mei driver */ 78*795536acSTomas Winkler err = pci_request_regions(pdev, KBUILD_MODNAME); 79*795536acSTomas Winkler if (err) { 80*795536acSTomas Winkler dev_err(&pdev->dev, "failed to get pci regions.\n"); 81*795536acSTomas Winkler goto disable_device; 82*795536acSTomas Winkler } 83*795536acSTomas Winkler 84*795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); 85*795536acSTomas Winkler if (err) { 86*795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 87*795536acSTomas Winkler if (err) { 88*795536acSTomas Winkler dev_err(&pdev->dev, "No suitable DMA available.\n"); 89*795536acSTomas Winkler goto release_regions; 90*795536acSTomas Winkler } 91*795536acSTomas Winkler } 92*795536acSTomas Winkler 93*795536acSTomas Winkler /* allocates and initializes the mei dev structure */ 94*795536acSTomas Winkler dev = mei_txe_dev_init(pdev); 95*795536acSTomas Winkler if (!dev) { 96*795536acSTomas Winkler err = -ENOMEM; 97*795536acSTomas Winkler goto release_regions; 98*795536acSTomas Winkler } 99*795536acSTomas Winkler hw = to_txe_hw(dev); 100*795536acSTomas Winkler 101*795536acSTomas Winkler /* mapping IO device memory */ 102*795536acSTomas Winkler for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { 103*795536acSTomas Winkler hw->mem_addr[i] = pci_iomap(pdev, i, 0); 104*795536acSTomas Winkler if (!hw->mem_addr[i]) { 105*795536acSTomas Winkler dev_err(&pdev->dev, "mapping I/O device memory failure.\n"); 106*795536acSTomas Winkler err = -ENOMEM; 107*795536acSTomas Winkler goto free_device; 108*795536acSTomas Winkler } 109*795536acSTomas Winkler } 110*795536acSTomas Winkler 111*795536acSTomas Winkler 112*795536acSTomas Winkler pci_enable_msi(pdev); 113*795536acSTomas Winkler 114*795536acSTomas Winkler /* clear spurious interrupts */ 115*795536acSTomas Winkler mei_clear_interrupts(dev); 116*795536acSTomas Winkler 117*795536acSTomas Winkler /* request and enable interrupt */ 118*795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 119*795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 120*795536acSTomas Winkler NULL, 121*795536acSTomas Winkler mei_txe_irq_thread_handler, 122*795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 123*795536acSTomas Winkler else 124*795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 125*795536acSTomas Winkler mei_txe_irq_quick_handler, 126*795536acSTomas Winkler mei_txe_irq_thread_handler, 127*795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 128*795536acSTomas Winkler if (err) { 129*795536acSTomas Winkler dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n", 130*795536acSTomas Winkler pdev->irq); 131*795536acSTomas Winkler goto free_device; 132*795536acSTomas Winkler } 133*795536acSTomas Winkler 134*795536acSTomas Winkler if (mei_start(dev)) { 135*795536acSTomas Winkler dev_err(&pdev->dev, "init hw failure.\n"); 136*795536acSTomas Winkler err = -ENODEV; 137*795536acSTomas Winkler goto release_irq; 138*795536acSTomas Winkler } 139*795536acSTomas Winkler 140*795536acSTomas Winkler err = mei_register(dev); 141*795536acSTomas Winkler if (err) 142*795536acSTomas Winkler goto release_irq; 143*795536acSTomas Winkler 144*795536acSTomas Winkler pci_set_drvdata(pdev, dev); 145*795536acSTomas Winkler 146*795536acSTomas Winkler return 0; 147*795536acSTomas Winkler 148*795536acSTomas Winkler release_irq: 149*795536acSTomas Winkler 150*795536acSTomas Winkler mei_cancel_work(dev); 151*795536acSTomas Winkler 152*795536acSTomas Winkler /* disable interrupts */ 153*795536acSTomas Winkler mei_disable_interrupts(dev); 154*795536acSTomas Winkler 155*795536acSTomas Winkler free_irq(pdev->irq, dev); 156*795536acSTomas Winkler pci_disable_msi(pdev); 157*795536acSTomas Winkler 158*795536acSTomas Winkler free_device: 159*795536acSTomas Winkler mei_txe_pci_iounmap(pdev, hw); 160*795536acSTomas Winkler 161*795536acSTomas Winkler kfree(dev); 162*795536acSTomas Winkler release_regions: 163*795536acSTomas Winkler pci_release_regions(pdev); 164*795536acSTomas Winkler disable_device: 165*795536acSTomas Winkler pci_disable_device(pdev); 166*795536acSTomas Winkler end: 167*795536acSTomas Winkler dev_err(&pdev->dev, "initialization failed.\n"); 168*795536acSTomas Winkler return err; 169*795536acSTomas Winkler } 170*795536acSTomas Winkler 171*795536acSTomas Winkler /** 172*795536acSTomas Winkler * mei_remove - Device Removal Routine 173*795536acSTomas Winkler * 174*795536acSTomas Winkler * @pdev: PCI device structure 175*795536acSTomas Winkler * 176*795536acSTomas Winkler * mei_remove is called by the PCI subsystem to alert the driver 177*795536acSTomas Winkler * that it should release a PCI device. 178*795536acSTomas Winkler */ 179*795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev) 180*795536acSTomas Winkler { 181*795536acSTomas Winkler struct mei_device *dev; 182*795536acSTomas Winkler struct mei_txe_hw *hw; 183*795536acSTomas Winkler 184*795536acSTomas Winkler dev = pci_get_drvdata(pdev); 185*795536acSTomas Winkler if (!dev) { 186*795536acSTomas Winkler dev_err(&pdev->dev, "mei: dev =NULL\n"); 187*795536acSTomas Winkler return; 188*795536acSTomas Winkler } 189*795536acSTomas Winkler 190*795536acSTomas Winkler hw = to_txe_hw(dev); 191*795536acSTomas Winkler 192*795536acSTomas Winkler mei_stop(dev); 193*795536acSTomas Winkler 194*795536acSTomas Winkler /* disable interrupts */ 195*795536acSTomas Winkler mei_disable_interrupts(dev); 196*795536acSTomas Winkler free_irq(pdev->irq, dev); 197*795536acSTomas Winkler pci_disable_msi(pdev); 198*795536acSTomas Winkler 199*795536acSTomas Winkler pci_set_drvdata(pdev, NULL); 200*795536acSTomas Winkler 201*795536acSTomas Winkler mei_txe_pci_iounmap(pdev, hw); 202*795536acSTomas Winkler 203*795536acSTomas Winkler mei_deregister(dev); 204*795536acSTomas Winkler 205*795536acSTomas Winkler kfree(dev); 206*795536acSTomas Winkler 207*795536acSTomas Winkler pci_release_regions(pdev); 208*795536acSTomas Winkler pci_disable_device(pdev); 209*795536acSTomas Winkler } 210*795536acSTomas Winkler 211*795536acSTomas Winkler 212*795536acSTomas Winkler #ifdef CONFIG_PM 213*795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device) 214*795536acSTomas Winkler { 215*795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 216*795536acSTomas Winkler struct mei_device *dev = pci_get_drvdata(pdev); 217*795536acSTomas Winkler 218*795536acSTomas Winkler if (!dev) 219*795536acSTomas Winkler return -ENODEV; 220*795536acSTomas Winkler 221*795536acSTomas Winkler dev_dbg(&pdev->dev, "suspend\n"); 222*795536acSTomas Winkler 223*795536acSTomas Winkler mei_stop(dev); 224*795536acSTomas Winkler 225*795536acSTomas Winkler mei_disable_interrupts(dev); 226*795536acSTomas Winkler 227*795536acSTomas Winkler free_irq(pdev->irq, dev); 228*795536acSTomas Winkler pci_disable_msi(pdev); 229*795536acSTomas Winkler 230*795536acSTomas Winkler return 0; 231*795536acSTomas Winkler } 232*795536acSTomas Winkler 233*795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device) 234*795536acSTomas Winkler { 235*795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 236*795536acSTomas Winkler struct mei_device *dev; 237*795536acSTomas Winkler int err; 238*795536acSTomas Winkler 239*795536acSTomas Winkler dev = pci_get_drvdata(pdev); 240*795536acSTomas Winkler if (!dev) 241*795536acSTomas Winkler return -ENODEV; 242*795536acSTomas Winkler 243*795536acSTomas Winkler pci_enable_msi(pdev); 244*795536acSTomas Winkler 245*795536acSTomas Winkler mei_clear_interrupts(dev); 246*795536acSTomas Winkler 247*795536acSTomas Winkler /* request and enable interrupt */ 248*795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 249*795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 250*795536acSTomas Winkler NULL, 251*795536acSTomas Winkler mei_txe_irq_thread_handler, 252*795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 253*795536acSTomas Winkler else 254*795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 255*795536acSTomas Winkler mei_txe_irq_quick_handler, 256*795536acSTomas Winkler mei_txe_irq_thread_handler, 257*795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 258*795536acSTomas Winkler if (err) { 259*795536acSTomas Winkler dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", 260*795536acSTomas Winkler pdev->irq); 261*795536acSTomas Winkler return err; 262*795536acSTomas Winkler } 263*795536acSTomas Winkler 264*795536acSTomas Winkler err = mei_restart(dev); 265*795536acSTomas Winkler 266*795536acSTomas Winkler return err; 267*795536acSTomas Winkler } 268*795536acSTomas Winkler 269*795536acSTomas Winkler static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops, 270*795536acSTomas Winkler mei_txe_pci_suspend, 271*795536acSTomas Winkler mei_txe_pci_resume); 272*795536acSTomas Winkler 273*795536acSTomas Winkler #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) 274*795536acSTomas Winkler #else 275*795536acSTomas Winkler #define MEI_TXE_PM_OPS NULL 276*795536acSTomas Winkler #endif /* CONFIG_PM */ 277*795536acSTomas Winkler /* 278*795536acSTomas Winkler * PCI driver structure 279*795536acSTomas Winkler */ 280*795536acSTomas Winkler static struct pci_driver mei_txe_driver = { 281*795536acSTomas Winkler .name = KBUILD_MODNAME, 282*795536acSTomas Winkler .id_table = mei_txe_pci_tbl, 283*795536acSTomas Winkler .probe = mei_txe_probe, 284*795536acSTomas Winkler .remove = mei_txe_remove, 285*795536acSTomas Winkler .shutdown = mei_txe_remove, 286*795536acSTomas Winkler .driver.pm = MEI_TXE_PM_OPS, 287*795536acSTomas Winkler }; 288*795536acSTomas Winkler 289*795536acSTomas Winkler module_pci_driver(mei_txe_driver); 290*795536acSTomas Winkler 291*795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation"); 292*795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface"); 293*795536acSTomas Winkler MODULE_LICENSE("GPL v2"); 294