diff options
author | Sudeep Dutt <sudeep.dutt@intel.com> | 2015-04-29 08:32:38 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-05-24 15:13:37 -0400 |
commit | 74321d4c99fc1d2582085cbb614d5a3ea9da962d (patch) | |
tree | 903b803d6a3ce4f7d49348b18b357dc69b4d4102 /drivers/misc/mic/host/mic_boot.c | |
parent | fdd9fd5c38afe732258a0af4c6be14f3fbd1585c (diff) |
misc: mic: MIC host driver specific changes to enable SCIF
MIC host driver specific changes to enable SCIF. This patch implements
the SCIF hardware bus operations and registers a SCIF device on the
SCIF hardware bus.
Reviewed-by: Nikhil Rao <nikhil.rao@intel.com>
Reviewed-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mic/host/mic_boot.c')
-rw-r--r-- | drivers/misc/mic/host/mic_boot.c | 264 |
1 files changed, 254 insertions, 10 deletions
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c index d9fa609da061..e5f6a5e7bca1 100644 --- a/drivers/misc/mic/host/mic_boot.c +++ b/drivers/misc/mic/host/mic_boot.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/firmware.h> | 22 | #include <linux/firmware.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/kmod.h> | ||
24 | 25 | ||
25 | #include <linux/mic_common.h> | 26 | #include <linux/mic_common.h> |
26 | #include <linux/mic_bus.h> | 27 | #include <linux/mic_bus.h> |
@@ -29,6 +30,188 @@ | |||
29 | #include "mic_smpt.h" | 30 | #include "mic_smpt.h" |
30 | #include "mic_virtio.h" | 31 | #include "mic_virtio.h" |
31 | 32 | ||
33 | static inline struct mic_device *scdev_to_mdev(struct scif_hw_dev *scdev) | ||
34 | { | ||
35 | return dev_get_drvdata(scdev->dev.parent); | ||
36 | } | ||
37 | |||
38 | static void *__mic_dma_alloc(struct device *dev, size_t size, | ||
39 | dma_addr_t *dma_handle, gfp_t gfp, | ||
40 | struct dma_attrs *attrs) | ||
41 | { | ||
42 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
43 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
44 | dma_addr_t tmp; | ||
45 | void *va = kmalloc(size, gfp); | ||
46 | |||
47 | if (va) { | ||
48 | tmp = mic_map_single(mdev, va, size); | ||
49 | if (dma_mapping_error(dev, tmp)) { | ||
50 | kfree(va); | ||
51 | va = NULL; | ||
52 | } else { | ||
53 | *dma_handle = tmp; | ||
54 | } | ||
55 | } | ||
56 | return va; | ||
57 | } | ||
58 | |||
59 | static void __mic_dma_free(struct device *dev, size_t size, void *vaddr, | ||
60 | dma_addr_t dma_handle, struct dma_attrs *attrs) | ||
61 | { | ||
62 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
63 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
64 | |||
65 | mic_unmap_single(mdev, dma_handle, size); | ||
66 | kfree(vaddr); | ||
67 | } | ||
68 | |||
69 | static dma_addr_t | ||
70 | __mic_dma_map_page(struct device *dev, struct page *page, unsigned long offset, | ||
71 | size_t size, enum dma_data_direction dir, | ||
72 | struct dma_attrs *attrs) | ||
73 | { | ||
74 | void *va = phys_to_virt(page_to_phys(page)) + offset; | ||
75 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
76 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
77 | |||
78 | return mic_map_single(mdev, va, size); | ||
79 | } | ||
80 | |||
81 | static void | ||
82 | __mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | ||
83 | size_t size, enum dma_data_direction dir, | ||
84 | struct dma_attrs *attrs) | ||
85 | { | ||
86 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
87 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
88 | |||
89 | mic_unmap_single(mdev, dma_addr, size); | ||
90 | } | ||
91 | |||
92 | static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
93 | int nents, enum dma_data_direction dir, | ||
94 | struct dma_attrs *attrs) | ||
95 | { | ||
96 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
97 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
98 | struct scatterlist *s; | ||
99 | int i, j, ret; | ||
100 | dma_addr_t da; | ||
101 | |||
102 | ret = dma_map_sg(mdev->sdev->parent, sg, nents, dir); | ||
103 | if (ret <= 0) | ||
104 | return 0; | ||
105 | |||
106 | for_each_sg(sg, s, nents, i) { | ||
107 | da = mic_map(mdev, sg_dma_address(s) + s->offset, s->length); | ||
108 | if (!da) | ||
109 | goto err; | ||
110 | sg_dma_address(s) = da; | ||
111 | } | ||
112 | return nents; | ||
113 | err: | ||
114 | for_each_sg(sg, s, i, j) { | ||
115 | mic_unmap(mdev, sg_dma_address(s), s->length); | ||
116 | sg_dma_address(s) = mic_to_dma_addr(mdev, sg_dma_address(s)); | ||
117 | } | ||
118 | dma_unmap_sg(mdev->sdev->parent, sg, nents, dir); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static void __mic_dma_unmap_sg(struct device *dev, | ||
123 | struct scatterlist *sg, int nents, | ||
124 | enum dma_data_direction dir, | ||
125 | struct dma_attrs *attrs) | ||
126 | { | ||
127 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | ||
128 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
129 | struct scatterlist *s; | ||
130 | dma_addr_t da; | ||
131 | int i; | ||
132 | |||
133 | for_each_sg(sg, s, nents, i) { | ||
134 | da = mic_to_dma_addr(mdev, sg_dma_address(s)); | ||
135 | mic_unmap(mdev, sg_dma_address(s), s->length); | ||
136 | sg_dma_address(s) = da; | ||
137 | } | ||
138 | dma_unmap_sg(mdev->sdev->parent, sg, nents, dir); | ||
139 | } | ||
140 | |||
141 | static struct dma_map_ops __mic_dma_ops = { | ||
142 | .alloc = __mic_dma_alloc, | ||
143 | .free = __mic_dma_free, | ||
144 | .map_page = __mic_dma_map_page, | ||
145 | .unmap_page = __mic_dma_unmap_page, | ||
146 | .map_sg = __mic_dma_map_sg, | ||
147 | .unmap_sg = __mic_dma_unmap_sg, | ||
148 | }; | ||
149 | |||
150 | static struct mic_irq * | ||
151 | ___mic_request_irq(struct scif_hw_dev *scdev, | ||
152 | irqreturn_t (*func)(int irq, void *data), | ||
153 | const char *name, | ||
154 | void *data, int db) | ||
155 | { | ||
156 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
157 | |||
158 | return mic_request_threaded_irq(mdev, func, NULL, name, data, | ||
159 | db, MIC_INTR_DB); | ||
160 | } | ||
161 | |||
162 | static void | ||
163 | ___mic_free_irq(struct scif_hw_dev *scdev, | ||
164 | struct mic_irq *cookie, void *data) | ||
165 | { | ||
166 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
167 | |||
168 | return mic_free_irq(mdev, cookie, data); | ||
169 | } | ||
170 | |||
171 | static void ___mic_ack_interrupt(struct scif_hw_dev *scdev, int num) | ||
172 | { | ||
173 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
174 | |||
175 | mdev->ops->intr_workarounds(mdev); | ||
176 | } | ||
177 | |||
178 | static int ___mic_next_db(struct scif_hw_dev *scdev) | ||
179 | { | ||
180 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
181 | |||
182 | return mic_next_db(mdev); | ||
183 | } | ||
184 | |||
185 | static void ___mic_send_intr(struct scif_hw_dev *scdev, int db) | ||
186 | { | ||
187 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
188 | |||
189 | mdev->ops->send_intr(mdev, db); | ||
190 | } | ||
191 | |||
192 | static void __iomem *___mic_ioremap(struct scif_hw_dev *scdev, | ||
193 | phys_addr_t pa, size_t len) | ||
194 | { | ||
195 | struct mic_device *mdev = scdev_to_mdev(scdev); | ||
196 | |||
197 | return mdev->aper.va + pa; | ||
198 | } | ||
199 | |||
200 | static void ___mic_iounmap(struct scif_hw_dev *scdev, void __iomem *va) | ||
201 | { | ||
202 | /* nothing to do */ | ||
203 | } | ||
204 | |||
205 | static struct scif_hw_ops scif_hw_ops = { | ||
206 | .request_irq = ___mic_request_irq, | ||
207 | .free_irq = ___mic_free_irq, | ||
208 | .ack_interrupt = ___mic_ack_interrupt, | ||
209 | .next_db = ___mic_next_db, | ||
210 | .send_intr = ___mic_send_intr, | ||
211 | .ioremap = ___mic_ioremap, | ||
212 | .iounmap = ___mic_iounmap, | ||
213 | }; | ||
214 | |||
32 | static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) | 215 | static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) |
33 | { | 216 | { |
34 | return dev_get_drvdata(mbdev->dev.parent); | 217 | return dev_get_drvdata(mbdev->dev.parent); |
@@ -127,6 +310,58 @@ void mic_bootparam_init(struct mic_device *mdev) | |||
127 | bootparam->h2c_config_db = -1; | 310 | bootparam->h2c_config_db = -1; |
128 | bootparam->shutdown_status = 0; | 311 | bootparam->shutdown_status = 0; |
129 | bootparam->shutdown_card = 0; | 312 | bootparam->shutdown_card = 0; |
313 | /* Total nodes = number of MICs + 1 for self node */ | ||
314 | bootparam->tot_nodes = atomic_read(&g_num_mics) + 1; | ||
315 | bootparam->node_id = mdev->id + 1; | ||
316 | bootparam->scif_host_dma_addr = 0x0; | ||
317 | bootparam->scif_card_dma_addr = 0x0; | ||
318 | bootparam->c2h_scif_db = -1; | ||
319 | bootparam->h2c_scif_db = -1; | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * mic_request_dma_chans - Request DMA channels | ||
324 | * @mdev: pointer to mic_device instance | ||
325 | * | ||
326 | * returns number of DMA channels acquired | ||
327 | */ | ||
328 | static int mic_request_dma_chans(struct mic_device *mdev) | ||
329 | { | ||
330 | dma_cap_mask_t mask; | ||
331 | struct dma_chan *chan; | ||
332 | |||
333 | request_module("mic_x100_dma"); | ||
334 | dma_cap_zero(mask); | ||
335 | dma_cap_set(DMA_MEMCPY, mask); | ||
336 | |||
337 | do { | ||
338 | chan = dma_request_channel(mask, mdev->ops->dma_filter, | ||
339 | mdev->sdev->parent); | ||
340 | if (chan) { | ||
341 | mdev->dma_ch[mdev->num_dma_ch++] = chan; | ||
342 | if (mdev->num_dma_ch >= MIC_MAX_DMA_CHAN) | ||
343 | break; | ||
344 | } | ||
345 | } while (chan); | ||
346 | dev_info(mdev->sdev->parent, "DMA channels # %d\n", mdev->num_dma_ch); | ||
347 | return mdev->num_dma_ch; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * mic_free_dma_chans - release DMA channels | ||
352 | * @mdev: pointer to mic_device instance | ||
353 | * | ||
354 | * returns none | ||
355 | */ | ||
356 | static void mic_free_dma_chans(struct mic_device *mdev) | ||
357 | { | ||
358 | int i = 0; | ||
359 | |||
360 | for (i = 0; i < mdev->num_dma_ch; i++) { | ||
361 | dma_release_channel(mdev->dma_ch[i]); | ||
362 | mdev->dma_ch[i] = NULL; | ||
363 | } | ||
364 | mdev->num_dma_ch = 0; | ||
130 | } | 365 | } |
131 | 366 | ||
132 | /** | 367 | /** |
@@ -141,6 +376,7 @@ int mic_start(struct mic_device *mdev, const char *buf) | |||
141 | { | 376 | { |
142 | int rc; | 377 | int rc; |
143 | mutex_lock(&mdev->mic_mutex); | 378 | mutex_lock(&mdev->mic_mutex); |
379 | mic_bootparam_init(mdev); | ||
144 | retry: | 380 | retry: |
145 | if (MIC_OFFLINE != mdev->state) { | 381 | if (MIC_OFFLINE != mdev->state) { |
146 | rc = -EINVAL; | 382 | rc = -EINVAL; |
@@ -161,14 +397,22 @@ retry: | |||
161 | rc = PTR_ERR(mdev->dma_mbdev); | 397 | rc = PTR_ERR(mdev->dma_mbdev); |
162 | goto unlock_ret; | 398 | goto unlock_ret; |
163 | } | 399 | } |
164 | mdev->dma_ch = mic_request_dma_chan(mdev); | 400 | if (!mic_request_dma_chans(mdev)) { |
165 | if (!mdev->dma_ch) { | 401 | rc = -ENODEV; |
166 | rc = -ENXIO; | ||
167 | goto dma_remove; | 402 | goto dma_remove; |
168 | } | 403 | } |
404 | mdev->scdev = scif_register_device(mdev->sdev->parent, MIC_SCIF_DEV, | ||
405 | &__mic_dma_ops, &scif_hw_ops, | ||
406 | mdev->id + 1, 0, &mdev->mmio, | ||
407 | &mdev->aper, mdev->dp, NULL, | ||
408 | mdev->dma_ch, mdev->num_dma_ch); | ||
409 | if (IS_ERR(mdev->scdev)) { | ||
410 | rc = PTR_ERR(mdev->scdev); | ||
411 | goto dma_free; | ||
412 | } | ||
169 | rc = mdev->ops->load_mic_fw(mdev, buf); | 413 | rc = mdev->ops->load_mic_fw(mdev, buf); |
170 | if (rc) | 414 | if (rc) |
171 | goto dma_release; | 415 | goto scif_remove; |
172 | mic_smpt_restore(mdev); | 416 | mic_smpt_restore(mdev); |
173 | mic_intr_restore(mdev); | 417 | mic_intr_restore(mdev); |
174 | mdev->intr_ops->enable_interrupts(mdev); | 418 | mdev->intr_ops->enable_interrupts(mdev); |
@@ -177,8 +421,10 @@ retry: | |||
177 | mdev->ops->send_firmware_intr(mdev); | 421 | mdev->ops->send_firmware_intr(mdev); |
178 | mic_set_state(mdev, MIC_ONLINE); | 422 | mic_set_state(mdev, MIC_ONLINE); |
179 | goto unlock_ret; | 423 | goto unlock_ret; |
180 | dma_release: | 424 | scif_remove: |
181 | dma_release_channel(mdev->dma_ch); | 425 | scif_unregister_device(mdev->scdev); |
426 | dma_free: | ||
427 | mic_free_dma_chans(mdev); | ||
182 | dma_remove: | 428 | dma_remove: |
183 | mbus_unregister_device(mdev->dma_mbdev); | 429 | mbus_unregister_device(mdev->dma_mbdev); |
184 | unlock_ret: | 430 | unlock_ret: |
@@ -197,11 +443,9 @@ void mic_stop(struct mic_device *mdev, bool force) | |||
197 | { | 443 | { |
198 | mutex_lock(&mdev->mic_mutex); | 444 | mutex_lock(&mdev->mic_mutex); |
199 | if (MIC_OFFLINE != mdev->state || force) { | 445 | if (MIC_OFFLINE != mdev->state || force) { |
446 | scif_unregister_device(mdev->scdev); | ||
200 | mic_virtio_reset_devices(mdev); | 447 | mic_virtio_reset_devices(mdev); |
201 | if (mdev->dma_ch) { | 448 | mic_free_dma_chans(mdev); |
202 | dma_release_channel(mdev->dma_ch); | ||
203 | mdev->dma_ch = NULL; | ||
204 | } | ||
205 | mbus_unregister_device(mdev->dma_mbdev); | 449 | mbus_unregister_device(mdev->dma_mbdev); |
206 | mic_bootparam_init(mdev); | 450 | mic_bootparam_init(mdev); |
207 | mic_reset(mdev); | 451 | mic_reset(mdev); |