1795536acSTomas Winkler /* 2795536acSTomas Winkler * 3795536acSTomas Winkler * Intel Management Engine Interface (Intel MEI) Linux driver 4795536acSTomas Winkler * Copyright (c) 2013-2014, Intel Corporation. 5795536acSTomas Winkler * 6795536acSTomas Winkler * This program is free software; you can redistribute it and/or modify it 7795536acSTomas Winkler * under the terms and conditions of the GNU General Public License, 8795536acSTomas Winkler * version 2, as published by the Free Software Foundation. 9795536acSTomas Winkler * 10795536acSTomas Winkler * This program is distributed in the hope it will be useful, but WITHOUT 11795536acSTomas Winkler * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12795536acSTomas Winkler * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13795536acSTomas Winkler * more details. 14795536acSTomas Winkler * 15795536acSTomas Winkler */ 16795536acSTomas Winkler 17795536acSTomas Winkler #include <linux/module.h> 18795536acSTomas Winkler #include <linux/kernel.h> 19795536acSTomas Winkler #include <linux/device.h> 20795536acSTomas Winkler #include <linux/fs.h> 21795536acSTomas Winkler #include <linux/errno.h> 22795536acSTomas Winkler #include <linux/types.h> 23795536acSTomas Winkler #include <linux/pci.h> 24795536acSTomas Winkler #include <linux/init.h> 25795536acSTomas Winkler #include <linux/sched.h> 26795536acSTomas Winkler #include <linux/uuid.h> 27795536acSTomas Winkler #include <linux/jiffies.h> 28795536acSTomas Winkler #include <linux/interrupt.h> 29795536acSTomas Winkler #include <linux/workqueue.h> 30795536acSTomas Winkler 31795536acSTomas Winkler #include <linux/mei.h> 32795536acSTomas Winkler 33795536acSTomas Winkler 34795536acSTomas Winkler #include "mei_dev.h" 35795536acSTomas Winkler #include "hw-txe.h" 36795536acSTomas Winkler 37*a05f8f86STomas Winkler static const struct pci_device_id mei_txe_pci_tbl[] = { 38795536acSTomas Winkler {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */ 39795536acSTomas Winkler {0, } 40795536acSTomas Winkler }; 41795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); 42795536acSTomas Winkler 43795536acSTomas Winkler 44795536acSTomas Winkler static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) 45795536acSTomas Winkler { 46795536acSTomas Winkler int i; 47795536acSTomas Winkler for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { 48795536acSTomas Winkler if (hw->mem_addr[i]) { 49795536acSTomas Winkler pci_iounmap(pdev, hw->mem_addr[i]); 50795536acSTomas Winkler hw->mem_addr[i] = NULL; 51795536acSTomas Winkler } 52795536acSTomas Winkler } 53795536acSTomas Winkler } 54795536acSTomas Winkler /** 55795536acSTomas Winkler * mei_probe - Device Initialization Routine 56795536acSTomas Winkler * 57795536acSTomas Winkler * @pdev: PCI device structure 58795536acSTomas Winkler * @ent: entry in mei_txe_pci_tbl 59795536acSTomas Winkler * 60795536acSTomas Winkler * returns 0 on success, <0 on failure. 61795536acSTomas Winkler */ 62795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 63795536acSTomas Winkler { 64795536acSTomas Winkler struct mei_device *dev; 65795536acSTomas Winkler struct mei_txe_hw *hw; 66795536acSTomas Winkler int err; 67795536acSTomas Winkler int i; 68795536acSTomas Winkler 69795536acSTomas Winkler /* enable pci dev */ 70795536acSTomas Winkler err = pci_enable_device(pdev); 71795536acSTomas Winkler if (err) { 72795536acSTomas Winkler dev_err(&pdev->dev, "failed to enable pci device.\n"); 73795536acSTomas Winkler goto end; 74795536acSTomas Winkler } 75795536acSTomas Winkler /* set PCI host mastering */ 76795536acSTomas Winkler pci_set_master(pdev); 77795536acSTomas Winkler /* pci request regions for mei driver */ 78795536acSTomas Winkler err = pci_request_regions(pdev, KBUILD_MODNAME); 79795536acSTomas Winkler if (err) { 80795536acSTomas Winkler dev_err(&pdev->dev, "failed to get pci regions.\n"); 81795536acSTomas Winkler goto disable_device; 82795536acSTomas Winkler } 83795536acSTomas Winkler 84795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); 85795536acSTomas Winkler if (err) { 86795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 87795536acSTomas Winkler if (err) { 88795536acSTomas Winkler dev_err(&pdev->dev, "No suitable DMA available.\n"); 89795536acSTomas Winkler goto release_regions; 90795536acSTomas Winkler } 91795536acSTomas Winkler } 92795536acSTomas Winkler 93795536acSTomas Winkler /* allocates and initializes the mei dev structure */ 94795536acSTomas Winkler dev = mei_txe_dev_init(pdev); 95795536acSTomas Winkler if (!dev) { 96795536acSTomas Winkler err = -ENOMEM; 97795536acSTomas Winkler goto release_regions; 98795536acSTomas Winkler } 99795536acSTomas Winkler hw = to_txe_hw(dev); 100795536acSTomas Winkler 101795536acSTomas Winkler /* mapping IO device memory */ 102795536acSTomas Winkler for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { 103795536acSTomas Winkler hw->mem_addr[i] = pci_iomap(pdev, i, 0); 104795536acSTomas Winkler if (!hw->mem_addr[i]) { 105795536acSTomas Winkler dev_err(&pdev->dev, "mapping I/O device memory failure.\n"); 106795536acSTomas Winkler err = -ENOMEM; 107795536acSTomas Winkler goto free_device; 108795536acSTomas Winkler } 109795536acSTomas Winkler } 110795536acSTomas Winkler 111795536acSTomas Winkler 112795536acSTomas Winkler pci_enable_msi(pdev); 113795536acSTomas Winkler 114795536acSTomas Winkler /* clear spurious interrupts */ 115795536acSTomas Winkler mei_clear_interrupts(dev); 116795536acSTomas Winkler 117795536acSTomas Winkler /* request and enable interrupt */ 118795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 119795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 120795536acSTomas Winkler NULL, 121795536acSTomas Winkler mei_txe_irq_thread_handler, 122795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 123795536acSTomas Winkler else 124795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 125795536acSTomas Winkler mei_txe_irq_quick_handler, 126795536acSTomas Winkler mei_txe_irq_thread_handler, 127795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 128795536acSTomas Winkler if (err) { 129795536acSTomas Winkler dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n", 130795536acSTomas Winkler pdev->irq); 131795536acSTomas Winkler goto free_device; 132795536acSTomas Winkler } 133795536acSTomas Winkler 134795536acSTomas Winkler if (mei_start(dev)) { 135795536acSTomas Winkler dev_err(&pdev->dev, "init hw failure.\n"); 136795536acSTomas Winkler err = -ENODEV; 137795536acSTomas Winkler goto release_irq; 138795536acSTomas Winkler } 139795536acSTomas Winkler 140795536acSTomas Winkler err = mei_register(dev); 141795536acSTomas Winkler if (err) 142795536acSTomas Winkler goto release_irq; 143795536acSTomas Winkler 144795536acSTomas Winkler pci_set_drvdata(pdev, dev); 145795536acSTomas Winkler 146795536acSTomas Winkler return 0; 147795536acSTomas Winkler 148795536acSTomas Winkler release_irq: 149795536acSTomas Winkler 150795536acSTomas Winkler mei_cancel_work(dev); 151795536acSTomas Winkler 152795536acSTomas Winkler /* disable interrupts */ 153795536acSTomas Winkler mei_disable_interrupts(dev); 154795536acSTomas Winkler 155795536acSTomas Winkler free_irq(pdev->irq, dev); 156795536acSTomas Winkler pci_disable_msi(pdev); 157795536acSTomas Winkler 158795536acSTomas Winkler free_device: 159795536acSTomas Winkler mei_txe_pci_iounmap(pdev, hw); 160795536acSTomas Winkler 161795536acSTomas Winkler kfree(dev); 162795536acSTomas Winkler release_regions: 163795536acSTomas Winkler pci_release_regions(pdev); 164795536acSTomas Winkler disable_device: 165795536acSTomas Winkler pci_disable_device(pdev); 166795536acSTomas Winkler end: 167795536acSTomas Winkler dev_err(&pdev->dev, "initialization failed.\n"); 168795536acSTomas Winkler return err; 169795536acSTomas Winkler } 170795536acSTomas Winkler 171795536acSTomas Winkler /** 172795536acSTomas Winkler * mei_remove - Device Removal Routine 173795536acSTomas Winkler * 174795536acSTomas Winkler * @pdev: PCI device structure 175795536acSTomas Winkler * 176795536acSTomas Winkler * mei_remove is called by the PCI subsystem to alert the driver 177795536acSTomas Winkler * that it should release a PCI device. 178795536acSTomas Winkler */ 179795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev) 180795536acSTomas Winkler { 181795536acSTomas Winkler struct mei_device *dev; 182795536acSTomas Winkler struct mei_txe_hw *hw; 183795536acSTomas Winkler 184795536acSTomas Winkler dev = pci_get_drvdata(pdev); 185795536acSTomas Winkler if (!dev) { 186795536acSTomas Winkler dev_err(&pdev->dev, "mei: dev =NULL\n"); 187795536acSTomas Winkler return; 188795536acSTomas Winkler } 189795536acSTomas Winkler 190795536acSTomas Winkler hw = to_txe_hw(dev); 191795536acSTomas Winkler 192795536acSTomas Winkler mei_stop(dev); 193795536acSTomas Winkler 194795536acSTomas Winkler /* disable interrupts */ 195795536acSTomas Winkler mei_disable_interrupts(dev); 196795536acSTomas Winkler free_irq(pdev->irq, dev); 197795536acSTomas Winkler pci_disable_msi(pdev); 198795536acSTomas Winkler 199795536acSTomas Winkler pci_set_drvdata(pdev, NULL); 200795536acSTomas Winkler 201795536acSTomas Winkler mei_txe_pci_iounmap(pdev, hw); 202795536acSTomas Winkler 203795536acSTomas Winkler mei_deregister(dev); 204795536acSTomas Winkler 205795536acSTomas Winkler kfree(dev); 206795536acSTomas Winkler 207795536acSTomas Winkler pci_release_regions(pdev); 208795536acSTomas Winkler pci_disable_device(pdev); 209795536acSTomas Winkler } 210795536acSTomas Winkler 211795536acSTomas Winkler 212e0270addSTomas Winkler #ifdef CONFIG_PM_SLEEP 213795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device) 214795536acSTomas Winkler { 215795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 216795536acSTomas Winkler struct mei_device *dev = pci_get_drvdata(pdev); 217795536acSTomas Winkler 218795536acSTomas Winkler if (!dev) 219795536acSTomas Winkler return -ENODEV; 220795536acSTomas Winkler 221795536acSTomas Winkler dev_dbg(&pdev->dev, "suspend\n"); 222795536acSTomas Winkler 223795536acSTomas Winkler mei_stop(dev); 224795536acSTomas Winkler 225795536acSTomas Winkler mei_disable_interrupts(dev); 226795536acSTomas Winkler 227795536acSTomas Winkler free_irq(pdev->irq, dev); 228795536acSTomas Winkler pci_disable_msi(pdev); 229795536acSTomas Winkler 230795536acSTomas Winkler return 0; 231795536acSTomas Winkler } 232795536acSTomas Winkler 233795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device) 234795536acSTomas Winkler { 235795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 236795536acSTomas Winkler struct mei_device *dev; 237795536acSTomas Winkler int err; 238795536acSTomas Winkler 239795536acSTomas Winkler dev = pci_get_drvdata(pdev); 240795536acSTomas Winkler if (!dev) 241795536acSTomas Winkler return -ENODEV; 242795536acSTomas Winkler 243795536acSTomas Winkler pci_enable_msi(pdev); 244795536acSTomas Winkler 245795536acSTomas Winkler mei_clear_interrupts(dev); 246795536acSTomas Winkler 247795536acSTomas Winkler /* request and enable interrupt */ 248795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 249795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 250795536acSTomas Winkler NULL, 251795536acSTomas Winkler mei_txe_irq_thread_handler, 252795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 253795536acSTomas Winkler else 254795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 255795536acSTomas Winkler mei_txe_irq_quick_handler, 256795536acSTomas Winkler mei_txe_irq_thread_handler, 257795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 258795536acSTomas Winkler if (err) { 259795536acSTomas Winkler dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", 260795536acSTomas Winkler pdev->irq); 261795536acSTomas Winkler return err; 262795536acSTomas Winkler } 263795536acSTomas Winkler 264795536acSTomas Winkler err = mei_restart(dev); 265795536acSTomas Winkler 266795536acSTomas Winkler return err; 267795536acSTomas Winkler } 268795536acSTomas Winkler 269795536acSTomas Winkler static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops, 270795536acSTomas Winkler mei_txe_pci_suspend, 271795536acSTomas Winkler mei_txe_pci_resume); 272795536acSTomas Winkler 273795536acSTomas Winkler #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) 274795536acSTomas Winkler #else 275795536acSTomas Winkler #define MEI_TXE_PM_OPS NULL 276e0270addSTomas Winkler #endif /* CONFIG_PM_SLEEP */ 277795536acSTomas Winkler /* 278795536acSTomas Winkler * PCI driver structure 279795536acSTomas Winkler */ 280795536acSTomas Winkler static struct pci_driver mei_txe_driver = { 281795536acSTomas Winkler .name = KBUILD_MODNAME, 282795536acSTomas Winkler .id_table = mei_txe_pci_tbl, 283795536acSTomas Winkler .probe = mei_txe_probe, 284795536acSTomas Winkler .remove = mei_txe_remove, 285795536acSTomas Winkler .shutdown = mei_txe_remove, 286795536acSTomas Winkler .driver.pm = MEI_TXE_PM_OPS, 287795536acSTomas Winkler }; 288795536acSTomas Winkler 289795536acSTomas Winkler module_pci_driver(mei_txe_driver); 290795536acSTomas Winkler 291795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation"); 292795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface"); 293795536acSTomas Winkler MODULE_LICENSE("GPL v2"); 294