Blame view

drivers/xen/platform-pci.c 4.68 KB
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /******************************************************************************
   * platform-pci.c
   *
   * Xen platform PCI device driver
   * Copyright (c) 2005, Intel Corporation.
   * Copyright (c) 2007, XenSource Inc.
   * Copyright (c) 2010, Citrix
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
   * Place - Suite 330, Boston, MA 02111-1307 USA.
   *
   */
  
  
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/module.h>
  #include <linux/pci.h>
c1c5413ad   Stefano Stabellini   x86: Unplug emula...
29
  #include <xen/platform_pci.h>
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
30
31
32
33
  #include <xen/grant_table.h>
  #include <xen/xenbus.h>
  #include <xen/events.h>
  #include <xen/hvm.h>
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
34
  #include <xen/xen-ops.h>
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
35
36
37
38
39
40
41
42
43
44
  
  #define DRV_NAME    "xen-platform-pci"
  
  MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com");
  MODULE_DESCRIPTION("Xen platform PCI device");
  MODULE_LICENSE("GPL");
  
  static unsigned long platform_mmio;
  static unsigned long platform_mmio_alloc;
  static unsigned long platform_mmiolen;
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
45
  static uint64_t callback_via;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  
  unsigned long alloc_xen_mmio(unsigned long len)
  {
  	unsigned long addr;
  
  	addr = platform_mmio + platform_mmio_alloc;
  	platform_mmio_alloc += len;
  	BUG_ON(platform_mmio_alloc > platform_mmiolen);
  
  	return addr;
  }
  
  static uint64_t get_callback_via(struct pci_dev *pdev)
  {
  	u8 pin;
  	int irq;
  
  	irq = pdev->irq;
  	if (irq < 16)
  		return irq; /* ISA IRQ */
  
  	pin = pdev->pin;
  
  	/* We don't know the GSI. Specify the PCI INTx line instead. */
  	return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */
  		((uint64_t)pci_domain_nr(pdev->bus) << 32) |
  		((uint64_t)pdev->bus->number << 16) |
  		((uint64_t)(pdev->devfn & 0xff) << 8) |
  		((uint64_t)(pin - 1) & 3);
  }
  
  static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
  {
  	xen_hvm_evtchn_do_upcall();
  	return IRQ_HANDLED;
  }
  
  static int xen_allocate_irq(struct pci_dev *pdev)
  {
  	return request_irq(pdev->irq, do_hvm_evtchn_intr,
  			IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
  			"xen-platform-pci", pdev);
  }
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
89
90
91
92
93
94
95
96
97
98
99
100
101
  static int platform_pci_resume(struct pci_dev *pdev)
  {
  	int err;
  	if (xen_have_vector_callback)
  		return 0;
  	err = xen_set_callback_via(callback_via);
  	if (err) {
  		dev_err(&pdev->dev, "platform_pci_resume failure!
  ");
  		return err;
  	}
  	return 0;
  }
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
102
103
104
105
  static int __devinit platform_pci_init(struct pci_dev *pdev,
  				       const struct pci_device_id *ent)
  {
  	int i, ret;
00f28e403   Ian Campbell   xen-platform: use...
106
  	long ioaddr;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
107
  	long mmio_addr, mmio_len;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
108
109
110
111
112
113
114
  	unsigned int max_nr_gframes;
  
  	i = pci_enable_device(pdev);
  	if (i)
  		return i;
  
  	ioaddr = pci_resource_start(pdev, 0);
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
115
116
117
118
119
120
121
122
123
124
  
  	mmio_addr = pci_resource_start(pdev, 1);
  	mmio_len = pci_resource_len(pdev, 1);
  
  	if (mmio_addr == 0 || ioaddr == 0) {
  		dev_err(&pdev->dev, "no resources found
  ");
  		ret = -ENOENT;
  		goto pci_out;
  	}
00f28e403   Ian Campbell   xen-platform: use...
125
126
  	ret = pci_request_region(pdev, 1, DRV_NAME);
  	if (ret < 0)
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
127
  		goto pci_out;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
128

00f28e403   Ian Campbell   xen-platform: use...
129
130
  	ret = pci_request_region(pdev, 0, DRV_NAME);
  	if (ret < 0)
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
131
  		goto mem_out;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  
  	platform_mmio = mmio_addr;
  	platform_mmiolen = mmio_len;
  
  	if (!xen_have_vector_callback) {
  		ret = xen_allocate_irq(pdev);
  		if (ret) {
  			dev_warn(&pdev->dev, "request_irq failed err=%d
  ", ret);
  			goto out;
  		}
  		callback_via = get_callback_via(pdev);
  		ret = xen_set_callback_via(callback_via);
  		if (ret) {
  			dev_warn(&pdev->dev, "Unable to set the evtchn callback "
  					 "err=%d
  ", ret);
  			goto out;
  		}
  	}
  
  	max_nr_gframes = gnttab_max_grant_frames();
  	xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
  	ret = gnttab_init();
  	if (ret)
  		goto out;
  	xenbus_probe(NULL);
  	return 0;
  
  out:
00f28e403   Ian Campbell   xen-platform: use...
162
  	pci_release_region(pdev, 0);
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
163
  mem_out:
00f28e403   Ian Campbell   xen-platform: use...
164
  	pci_release_region(pdev, 1);
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  pci_out:
  	pci_disable_device(pdev);
  	return ret;
  }
  
  static struct pci_device_id platform_pci_tbl[] __devinitdata = {
  	{PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
  		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{0,}
  };
  
  MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
  
  static struct pci_driver platform_driver = {
  	.name =           DRV_NAME,
  	.probe =          platform_pci_init,
  	.id_table =       platform_pci_tbl,
016b6f5fe   Stefano Stabellini   xen: Add suspend/...
182
183
184
  #ifdef CONFIG_PM
  	.resume_early =   platform_pci_resume,
  #endif
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
185
186
187
188
  };
  
  static int __init platform_pci_module_init(void)
  {
c1c5413ad   Stefano Stabellini   x86: Unplug emula...
189
190
191
192
  	/* no unplug has been done, IGNORE hasn't been specified: just
  	 * return now */
  	if (!xen_platform_pci_unplug)
  		return -ENODEV;
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
193
194
195
196
  	return pci_register_driver(&platform_driver);
  }
  
  module_init(platform_pci_module_init);