Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /******************************************************************************
0003  * platform-pci.c
0004  *
0005  * Xen platform PCI device driver
0006  *
0007  * Authors: ssmith@xensource.com and stefano.stabellini@eu.citrix.com
0008  *
0009  * Copyright (c) 2005, Intel Corporation.
0010  * Copyright (c) 2007, XenSource Inc.
0011  * Copyright (c) 2010, Citrix
0012  */
0013 
0014 
0015 #include <linux/interrupt.h>
0016 #include <linux/io.h>
0017 #include <linux/init.h>
0018 #include <linux/pci.h>
0019 
0020 #include <xen/platform_pci.h>
0021 #include <xen/grant_table.h>
0022 #include <xen/xenbus.h>
0023 #include <xen/events.h>
0024 #include <xen/hvm.h>
0025 #include <xen/xen-ops.h>
0026 
0027 #define DRV_NAME    "xen-platform-pci"
0028 
0029 static unsigned long platform_mmio;
0030 static unsigned long platform_mmio_alloc;
0031 static unsigned long platform_mmiolen;
0032 static uint64_t callback_via;
0033 
0034 static unsigned long alloc_xen_mmio(unsigned long len)
0035 {
0036     unsigned long addr;
0037 
0038     addr = platform_mmio + platform_mmio_alloc;
0039     platform_mmio_alloc += len;
0040     BUG_ON(platform_mmio_alloc > platform_mmiolen);
0041 
0042     return addr;
0043 }
0044 
0045 static uint64_t get_callback_via(struct pci_dev *pdev)
0046 {
0047     u8 pin;
0048     int irq;
0049 
0050     irq = pdev->irq;
0051     if (irq < 16)
0052         return irq; /* ISA IRQ */
0053 
0054     pin = pdev->pin;
0055 
0056     /* We don't know the GSI. Specify the PCI INTx line instead. */
0057     return ((uint64_t)0x01 << HVM_CALLBACK_VIA_TYPE_SHIFT) | /* PCI INTx identifier */
0058         ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
0059         ((uint64_t)pdev->bus->number << 16) |
0060         ((uint64_t)(pdev->devfn & 0xff) << 8) |
0061         ((uint64_t)(pin - 1) & 3);
0062 }
0063 
0064 static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
0065 {
0066     xen_hvm_evtchn_do_upcall();
0067     return IRQ_HANDLED;
0068 }
0069 
0070 static int xen_allocate_irq(struct pci_dev *pdev)
0071 {
0072     return request_irq(pdev->irq, do_hvm_evtchn_intr,
0073             IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
0074             "xen-platform-pci", pdev);
0075 }
0076 
0077 static int platform_pci_resume(struct device *dev)
0078 {
0079     int err;
0080 
0081     if (xen_have_vector_callback)
0082         return 0;
0083 
0084     err = xen_set_callback_via(callback_via);
0085     if (err) {
0086         dev_err(dev, "platform_pci_resume failure!\n");
0087         return err;
0088     }
0089     return 0;
0090 }
0091 
0092 static int platform_pci_probe(struct pci_dev *pdev,
0093                   const struct pci_device_id *ent)
0094 {
0095     int i, ret;
0096     long ioaddr;
0097     long mmio_addr, mmio_len;
0098     unsigned int max_nr_gframes;
0099     unsigned long grant_frames;
0100 
0101     if (!xen_domain())
0102         return -ENODEV;
0103 
0104     i = pci_enable_device(pdev);
0105     if (i)
0106         return i;
0107 
0108     ioaddr = pci_resource_start(pdev, 0);
0109 
0110     mmio_addr = pci_resource_start(pdev, 1);
0111     mmio_len = pci_resource_len(pdev, 1);
0112 
0113     if (mmio_addr == 0 || ioaddr == 0) {
0114         dev_err(&pdev->dev, "no resources found\n");
0115         ret = -ENOENT;
0116         goto pci_out;
0117     }
0118 
0119     ret = pci_request_region(pdev, 1, DRV_NAME);
0120     if (ret < 0)
0121         goto pci_out;
0122 
0123     ret = pci_request_region(pdev, 0, DRV_NAME);
0124     if (ret < 0)
0125         goto mem_out;
0126 
0127     platform_mmio = mmio_addr;
0128     platform_mmiolen = mmio_len;
0129     if (!xen_have_vector_callback) {
0130         ret = xen_allocate_irq(pdev);
0131         if (ret) {
0132             dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
0133             goto out;
0134         }
0135         /*
0136          * It doesn't strictly *have* to run on CPU0 but it sure
0137          * as hell better process the event channel ports delivered
0138          * to CPU0.
0139          */
0140         irq_set_affinity(pdev->irq, cpumask_of(0));
0141 
0142         callback_via = get_callback_via(pdev);
0143         ret = xen_set_callback_via(callback_via);
0144         if (ret) {
0145             dev_warn(&pdev->dev, "Unable to set the evtchn callback "
0146                      "err=%d\n", ret);
0147             goto out;
0148         }
0149     }
0150 
0151     max_nr_gframes = gnttab_max_grant_frames();
0152     grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
0153     ret = gnttab_setup_auto_xlat_frames(grant_frames);
0154     if (ret)
0155         goto out;
0156     ret = gnttab_init();
0157     if (ret)
0158         goto grant_out;
0159     return 0;
0160 grant_out:
0161     gnttab_free_auto_xlat_frames();
0162 out:
0163     pci_release_region(pdev, 0);
0164 mem_out:
0165     pci_release_region(pdev, 1);
0166 pci_out:
0167     pci_disable_device(pdev);
0168     return ret;
0169 }
0170 
0171 static const struct pci_device_id platform_pci_tbl[] = {
0172     {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
0173         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
0174     {0,}
0175 };
0176 
0177 static const struct dev_pm_ops platform_pm_ops = {
0178     .resume_noirq =   platform_pci_resume,
0179 };
0180 
0181 static struct pci_driver platform_driver = {
0182     .name =           DRV_NAME,
0183     .probe =          platform_pci_probe,
0184     .id_table =       platform_pci_tbl,
0185     .driver = {
0186         .pm =     &platform_pm_ops,
0187     },
0188 };
0189 
0190 builtin_pci_driver(platform_driver);