]>
Commit | Line | Data |
---|---|---|
b170d8ce SD |
1 | /* |
2 | * Intel MIC Platform Software Stack (MPSS) | |
3 | * | |
4 | * Copyright(c) 2013 Intel Corporation. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License, version 2, as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License for more details. | |
14 | * | |
15 | * The full GNU General Public License is included in this distribution in | |
16 | * the file called "COPYING". | |
17 | * | |
18 | * Intel MIC Host driver. | |
b170d8ce SD |
19 | */ |
20 | #include <linux/fs.h> | |
b170d8ce SD |
21 | #include <linux/module.h> |
22 | #include <linux/pci.h> | |
f69bcbf3 | 23 | #include <linux/poll.h> |
b170d8ce | 24 | |
3a6a9201 | 25 | #include <linux/mic_common.h> |
4aa79961 | 26 | #include "../common/mic_dev.h" |
b170d8ce SD |
27 | #include "mic_device.h" |
28 | #include "mic_x100.h" | |
a01e28f6 | 29 | #include "mic_smpt.h" |
b170d8ce SD |
30 | |
31 | static const char mic_driver_name[] = "mic"; | |
32 | ||
32182cd3 | 33 | static const struct pci_device_id mic_pci_tbl[] = { |
b170d8ce SD |
34 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2250)}, |
35 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2251)}, | |
36 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2252)}, | |
37 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2253)}, | |
38 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2254)}, | |
39 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2255)}, | |
40 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2256)}, | |
41 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2257)}, | |
42 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2258)}, | |
43 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2259)}, | |
44 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225a)}, | |
45 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225b)}, | |
46 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225c)}, | |
47 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225d)}, | |
48 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225e)}, | |
49 | ||
50 | /* required last entry */ | |
51 | { 0, } | |
52 | }; | |
53 | ||
54 | MODULE_DEVICE_TABLE(pci, mic_pci_tbl); | |
55 | ||
56 | /* ID allocator for MIC devices */ | |
57 | static struct ida g_mic_ida; | |
f69bcbf3 | 58 | |
3a6a9201 SD |
59 | /* Initialize the device page */ |
60 | static int mic_dp_init(struct mic_device *mdev) | |
61 | { | |
62 | mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL); | |
1da2b3ee | 63 | if (!mdev->dp) |
3a6a9201 | 64 | return -ENOMEM; |
3a6a9201 SD |
65 | |
66 | mdev->dp_dma_addr = mic_map_single(mdev, | |
67 | mdev->dp, MIC_DP_SIZE); | |
68 | if (mic_map_error(mdev->dp_dma_addr)) { | |
69 | kfree(mdev->dp); | |
1da2b3ee | 70 | dev_err(&mdev->pdev->dev, "%s %d err %d\n", |
3a6a9201 SD |
71 | __func__, __LINE__, -ENOMEM); |
72 | return -ENOMEM; | |
73 | } | |
74 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | |
75 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | |
76 | return 0; | |
77 | } | |
78 | ||
79 | /* Uninitialize the device page */ | |
80 | static void mic_dp_uninit(struct mic_device *mdev) | |
81 | { | |
82 | mic_unmap_single(mdev, mdev->dp_dma_addr, MIC_DP_SIZE); | |
83 | kfree(mdev->dp); | |
84 | } | |
85 | ||
b170d8ce SD |
86 | /** |
87 | * mic_ops_init: Initialize HW specific operation tables. | |
88 | * | |
89 | * @mdev: pointer to mic_device instance | |
90 | * | |
91 | * returns none. | |
92 | */ | |
93 | static void mic_ops_init(struct mic_device *mdev) | |
94 | { | |
95 | switch (mdev->family) { | |
96 | case MIC_FAMILY_X100: | |
97 | mdev->ops = &mic_x100_ops; | |
a01e28f6 DC |
98 | mdev->intr_ops = &mic_x100_intr_ops; |
99 | mdev->smpt_ops = &mic_x100_smpt_ops; | |
b170d8ce SD |
100 | break; |
101 | default: | |
102 | break; | |
103 | } | |
104 | } | |
105 | ||
106 | /** | |
107 | * mic_get_family - Determine hardware family to which this MIC belongs. | |
108 | * | |
109 | * @pdev: The pci device structure | |
110 | * | |
111 | * returns family. | |
112 | */ | |
113 | static enum mic_hw_family mic_get_family(struct pci_dev *pdev) | |
114 | { | |
115 | enum mic_hw_family family; | |
116 | ||
117 | switch (pdev->device) { | |
118 | case MIC_X100_PCI_DEVICE_2250: | |
119 | case MIC_X100_PCI_DEVICE_2251: | |
120 | case MIC_X100_PCI_DEVICE_2252: | |
121 | case MIC_X100_PCI_DEVICE_2253: | |
122 | case MIC_X100_PCI_DEVICE_2254: | |
123 | case MIC_X100_PCI_DEVICE_2255: | |
124 | case MIC_X100_PCI_DEVICE_2256: | |
125 | case MIC_X100_PCI_DEVICE_2257: | |
126 | case MIC_X100_PCI_DEVICE_2258: | |
127 | case MIC_X100_PCI_DEVICE_2259: | |
128 | case MIC_X100_PCI_DEVICE_225a: | |
129 | case MIC_X100_PCI_DEVICE_225b: | |
130 | case MIC_X100_PCI_DEVICE_225c: | |
131 | case MIC_X100_PCI_DEVICE_225d: | |
132 | case MIC_X100_PCI_DEVICE_225e: | |
133 | family = MIC_FAMILY_X100; | |
134 | break; | |
135 | default: | |
136 | family = MIC_FAMILY_UNKNOWN; | |
137 | break; | |
138 | } | |
139 | return family; | |
140 | } | |
141 | ||
142 | /** | |
143 | * mic_device_init - Allocates and initializes the MIC device structure | |
144 | * | |
145 | * @mdev: pointer to mic_device instance | |
146 | * @pdev: The pci device structure | |
147 | * | |
148 | * returns none. | |
149 | */ | |
1da2b3ee | 150 | static void |
b170d8ce SD |
151 | mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) |
152 | { | |
1da2b3ee | 153 | mdev->pdev = pdev; |
b170d8ce SD |
154 | mdev->family = mic_get_family(pdev); |
155 | mdev->stepping = pdev->revision; | |
156 | mic_ops_init(mdev); | |
a01e28f6 DC |
157 | mutex_init(&mdev->mic_mutex); |
158 | mdev->irq_info.next_avail_src = 0; | |
b170d8ce SD |
159 | } |
160 | ||
161 | /** | |
162 | * mic_probe - Device Initialization Routine | |
163 | * | |
164 | * @pdev: PCI device structure | |
165 | * @ent: entry in mic_pci_tbl | |
166 | * | |
167 | * returns 0 on success, < 0 on failure. | |
168 | */ | |
169 | static int mic_probe(struct pci_dev *pdev, | |
1da2b3ee | 170 | const struct pci_device_id *ent) |
b170d8ce SD |
171 | { |
172 | int rc; | |
173 | struct mic_device *mdev; | |
174 | ||
175 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | |
176 | if (!mdev) { | |
177 | rc = -ENOMEM; | |
178 | dev_err(&pdev->dev, "mdev kmalloc failed rc %d\n", rc); | |
179 | goto mdev_alloc_fail; | |
180 | } | |
181 | mdev->id = ida_simple_get(&g_mic_ida, 0, MIC_MAX_NUM_DEVS, GFP_KERNEL); | |
182 | if (mdev->id < 0) { | |
183 | rc = mdev->id; | |
184 | dev_err(&pdev->dev, "ida_simple_get failed rc %d\n", rc); | |
185 | goto ida_fail; | |
186 | } | |
187 | ||
1da2b3ee | 188 | mic_device_init(mdev, pdev); |
b170d8ce SD |
189 | |
190 | rc = pci_enable_device(pdev); | |
191 | if (rc) { | |
192 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | |
1da2b3ee | 193 | goto ida_remove; |
b170d8ce SD |
194 | } |
195 | ||
196 | pci_set_master(pdev); | |
197 | ||
198 | rc = pci_request_regions(pdev, mic_driver_name); | |
199 | if (rc) { | |
200 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | |
201 | goto disable_device; | |
202 | } | |
203 | ||
204 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | |
205 | if (rc) { | |
206 | dev_err(&pdev->dev, "Cannot set DMA mask\n"); | |
207 | goto release_regions; | |
208 | } | |
209 | ||
210 | mdev->mmio.pa = pci_resource_start(pdev, mdev->ops->mmio_bar); | |
211 | mdev->mmio.len = pci_resource_len(pdev, mdev->ops->mmio_bar); | |
212 | mdev->mmio.va = pci_ioremap_bar(pdev, mdev->ops->mmio_bar); | |
213 | if (!mdev->mmio.va) { | |
214 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); | |
215 | rc = -EIO; | |
216 | goto release_regions; | |
217 | } | |
218 | ||
219 | mdev->aper.pa = pci_resource_start(pdev, mdev->ops->aper_bar); | |
220 | mdev->aper.len = pci_resource_len(pdev, mdev->ops->aper_bar); | |
221 | mdev->aper.va = ioremap_wc(mdev->aper.pa, mdev->aper.len); | |
222 | if (!mdev->aper.va) { | |
223 | dev_err(&pdev->dev, "Cannot remap Aperture BAR\n"); | |
224 | rc = -EIO; | |
225 | goto unmap_mmio; | |
226 | } | |
227 | ||
a01e28f6 DC |
228 | mdev->intr_ops->intr_init(mdev); |
229 | rc = mic_setup_interrupts(mdev, pdev); | |
230 | if (rc) { | |
231 | dev_err(&pdev->dev, "mic_setup_interrupts failed %d\n", rc); | |
232 | goto unmap_aper; | |
233 | } | |
234 | rc = mic_smpt_init(mdev); | |
235 | if (rc) { | |
236 | dev_err(&pdev->dev, "smpt_init failed %d\n", rc); | |
237 | goto free_interrupts; | |
238 | } | |
239 | ||
b170d8ce SD |
240 | pci_set_drvdata(pdev, mdev); |
241 | ||
3a6a9201 SD |
242 | rc = mic_dp_init(mdev); |
243 | if (rc) { | |
244 | dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc); | |
1da2b3ee | 245 | goto smpt_uninit; |
3a6a9201 | 246 | } |
3a6a9201 | 247 | mic_bootparam_init(mdev); |
3a6a9201 | 248 | mic_create_debug_dir(mdev); |
1da2b3ee | 249 | |
1da2b3ee AD |
250 | mdev->cosm_dev = cosm_register_device(&mdev->pdev->dev, &cosm_hw_ops); |
251 | if (IS_ERR(mdev->cosm_dev)) { | |
252 | rc = PTR_ERR(mdev->cosm_dev); | |
253 | dev_err(&pdev->dev, "cosm_add_device failed rc %d\n", rc); | |
ef39830c | 254 | goto cleanup_debug_dir; |
1da2b3ee | 255 | } |
b170d8ce | 256 | return 0; |
f69bcbf3 AD |
257 | cleanup_debug_dir: |
258 | mic_delete_debug_dir(mdev); | |
3a6a9201 | 259 | mic_dp_uninit(mdev); |
a01e28f6 DC |
260 | smpt_uninit: |
261 | mic_smpt_uninit(mdev); | |
262 | free_interrupts: | |
263 | mic_free_interrupts(mdev, pdev); | |
b170d8ce SD |
264 | unmap_aper: |
265 | iounmap(mdev->aper.va); | |
266 | unmap_mmio: | |
267 | iounmap(mdev->mmio.va); | |
268 | release_regions: | |
269 | pci_release_regions(pdev); | |
270 | disable_device: | |
271 | pci_disable_device(pdev); | |
1da2b3ee | 272 | ida_remove: |
b170d8ce SD |
273 | ida_simple_remove(&g_mic_ida, mdev->id); |
274 | ida_fail: | |
275 | kfree(mdev); | |
276 | mdev_alloc_fail: | |
277 | dev_err(&pdev->dev, "Probe failed rc %d\n", rc); | |
278 | return rc; | |
279 | } | |
280 | ||
281 | /** | |
282 | * mic_remove - Device Removal Routine | |
283 | * mic_remove is called by the PCI subsystem to alert the driver | |
284 | * that it should release a PCI device. | |
285 | * | |
286 | * @pdev: PCI device structure | |
287 | */ | |
288 | static void mic_remove(struct pci_dev *pdev) | |
289 | { | |
290 | struct mic_device *mdev; | |
291 | ||
292 | mdev = pci_get_drvdata(pdev); | |
293 | if (!mdev) | |
294 | return; | |
295 | ||
1da2b3ee | 296 | cosm_unregister_device(mdev->cosm_dev); |
3a6a9201 | 297 | mic_delete_debug_dir(mdev); |
3a6a9201 | 298 | mic_dp_uninit(mdev); |
a01e28f6 DC |
299 | mic_smpt_uninit(mdev); |
300 | mic_free_interrupts(mdev, pdev); | |
b170d8ce | 301 | iounmap(mdev->aper.va); |
1da2b3ee | 302 | iounmap(mdev->mmio.va); |
b170d8ce SD |
303 | pci_release_regions(pdev); |
304 | pci_disable_device(pdev); | |
305 | ida_simple_remove(&g_mic_ida, mdev->id); | |
306 | kfree(mdev); | |
307 | } | |
74321d4c | 308 | |
b170d8ce SD |
309 | static struct pci_driver mic_driver = { |
310 | .name = mic_driver_name, | |
311 | .id_table = mic_pci_tbl, | |
312 | .probe = mic_probe, | |
313 | .remove = mic_remove | |
314 | }; | |
315 | ||
316 | static int __init mic_init(void) | |
317 | { | |
318 | int ret; | |
319 | ||
c74c9318 | 320 | request_module("mic_x100_dma"); |
3a6a9201 | 321 | mic_init_debugfs(); |
b170d8ce SD |
322 | ida_init(&g_mic_ida); |
323 | ret = pci_register_driver(&mic_driver); | |
324 | if (ret) { | |
325 | pr_err("pci_register_driver failed ret %d\n", ret); | |
ef39830c | 326 | goto cleanup_debugfs; |
b170d8ce | 327 | } |
ef39830c SD |
328 | return 0; |
329 | cleanup_debugfs: | |
74321d4c | 330 | ida_destroy(&g_mic_ida); |
3a6a9201 | 331 | mic_exit_debugfs(); |
b170d8ce SD |
332 | return ret; |
333 | } | |
334 | ||
335 | static void __exit mic_exit(void) | |
336 | { | |
337 | pci_unregister_driver(&mic_driver); | |
338 | ida_destroy(&g_mic_ida); | |
3a6a9201 | 339 | mic_exit_debugfs(); |
b170d8ce SD |
340 | } |
341 | ||
342 | module_init(mic_init); | |
343 | module_exit(mic_exit); | |
344 | ||
345 | MODULE_AUTHOR("Intel Corporation"); | |
346 | MODULE_DESCRIPTION("Intel(R) MIC X100 Host driver"); | |
347 | MODULE_LICENSE("GPL v2"); |