Commit | Line | Data |
---|---|---|
3a6a9201 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. | |
19 | * | |
20 | */ | |
21 | #include <linux/delay.h> | |
22 | #include <linux/firmware.h> | |
42579226 | 23 | #include <linux/pci.h> |
74321d4c | 24 | #include <linux/kmod.h> |
3a6a9201 | 25 | #include <linux/mic_common.h> |
d4ef098e | 26 | #include <linux/mic_bus.h> |
1da2b3ee | 27 | #include "../bus/scif_bus.h" |
c74c9318 | 28 | #include "../bus/vop_bus.h" |
4aa79961 | 29 | #include "../common/mic_dev.h" |
3a6a9201 SD |
30 | #include "mic_device.h" |
31 | #include "mic_smpt.h" | |
32 | ||
c74c9318 SD |
33 | static inline struct mic_device *vpdev_to_mdev(struct device *dev) |
34 | { | |
35 | return dev_get_drvdata(dev->parent); | |
36 | } | |
37 | ||
38 | static dma_addr_t | |
39 | _mic_dma_map_page(struct device *dev, struct page *page, | |
40 | unsigned long offset, size_t size, | |
00085f1e | 41 | enum dma_data_direction dir, unsigned long attrs) |
c74c9318 SD |
42 | { |
43 | void *va = phys_to_virt(page_to_phys(page)) + offset; | |
44 | struct mic_device *mdev = vpdev_to_mdev(dev); | |
45 | ||
46 | return mic_map_single(mdev, va, size); | |
47 | } | |
48 | ||
49 | static void _mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | |
50 | size_t size, enum dma_data_direction dir, | |
00085f1e | 51 | unsigned long attrs) |
c74c9318 SD |
52 | { |
53 | struct mic_device *mdev = vpdev_to_mdev(dev); | |
54 | ||
55 | mic_unmap_single(mdev, dma_addr, size); | |
56 | } | |
57 | ||
58 | static const struct dma_map_ops _mic_dma_ops = { | |
59 | .map_page = _mic_dma_map_page, | |
60 | .unmap_page = _mic_dma_unmap_page, | |
61 | }; | |
62 | ||
63 | static struct mic_irq * | |
64 | __mic_request_irq(struct vop_device *vpdev, | |
65 | irqreturn_t (*func)(int irq, void *data), | |
66 | const char *name, void *data, int intr_src) | |
67 | { | |
68 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
69 | ||
70 | return mic_request_threaded_irq(mdev, func, NULL, name, data, | |
71 | intr_src, MIC_INTR_DB); | |
72 | } | |
73 | ||
74 | static void __mic_free_irq(struct vop_device *vpdev, | |
75 | struct mic_irq *cookie, void *data) | |
76 | { | |
77 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
78 | ||
fee26876 | 79 | mic_free_irq(mdev, cookie, data); |
c74c9318 SD |
80 | } |
81 | ||
82 | static void __mic_ack_interrupt(struct vop_device *vpdev, int num) | |
83 | { | |
84 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
85 | ||
86 | mdev->ops->intr_workarounds(mdev); | |
87 | } | |
88 | ||
89 | static int __mic_next_db(struct vop_device *vpdev) | |
90 | { | |
91 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
92 | ||
93 | return mic_next_db(mdev); | |
94 | } | |
95 | ||
96 | static void *__mic_get_dp(struct vop_device *vpdev) | |
97 | { | |
98 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
99 | ||
100 | return mdev->dp; | |
101 | } | |
102 | ||
103 | static void __iomem *__mic_get_remote_dp(struct vop_device *vpdev) | |
104 | { | |
105 | return NULL; | |
106 | } | |
107 | ||
108 | static void __mic_send_intr(struct vop_device *vpdev, int db) | |
109 | { | |
110 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
111 | ||
112 | mdev->ops->send_intr(mdev, db); | |
113 | } | |
114 | ||
115 | static void __iomem *__mic_ioremap(struct vop_device *vpdev, | |
116 | dma_addr_t pa, size_t len) | |
117 | { | |
118 | struct mic_device *mdev = vpdev_to_mdev(&vpdev->dev); | |
119 | ||
120 | return mdev->aper.va + pa; | |
121 | } | |
122 | ||
123 | static void __mic_iounmap(struct vop_device *vpdev, void __iomem *va) | |
124 | { | |
125 | /* nothing to do */ | |
126 | } | |
127 | ||
128 | static struct vop_hw_ops vop_hw_ops = { | |
129 | .request_irq = __mic_request_irq, | |
130 | .free_irq = __mic_free_irq, | |
131 | .ack_interrupt = __mic_ack_interrupt, | |
132 | .next_db = __mic_next_db, | |
133 | .get_dp = __mic_get_dp, | |
134 | .get_remote_dp = __mic_get_remote_dp, | |
135 | .send_intr = __mic_send_intr, | |
136 | .ioremap = __mic_ioremap, | |
137 | .iounmap = __mic_iounmap, | |
138 | }; | |
139 | ||
74321d4c SD |
140 | static inline struct mic_device *scdev_to_mdev(struct scif_hw_dev *scdev) |
141 | { | |
142 | return dev_get_drvdata(scdev->dev.parent); | |
143 | } | |
144 | ||
145 | static void *__mic_dma_alloc(struct device *dev, size_t size, | |
146 | dma_addr_t *dma_handle, gfp_t gfp, | |
00085f1e | 147 | unsigned long attrs) |
74321d4c SD |
148 | { |
149 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
150 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
151 | dma_addr_t tmp; | |
152 | void *va = kmalloc(size, gfp); | |
153 | ||
154 | if (va) { | |
155 | tmp = mic_map_single(mdev, va, size); | |
156 | if (dma_mapping_error(dev, tmp)) { | |
157 | kfree(va); | |
158 | va = NULL; | |
159 | } else { | |
160 | *dma_handle = tmp; | |
161 | } | |
162 | } | |
163 | return va; | |
164 | } | |
165 | ||
166 | static void __mic_dma_free(struct device *dev, size_t size, void *vaddr, | |
00085f1e | 167 | dma_addr_t dma_handle, unsigned long attrs) |
74321d4c SD |
168 | { |
169 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
170 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
171 | ||
172 | mic_unmap_single(mdev, dma_handle, size); | |
173 | kfree(vaddr); | |
174 | } | |
175 | ||
176 | static dma_addr_t | |
177 | __mic_dma_map_page(struct device *dev, struct page *page, unsigned long offset, | |
178 | size_t size, enum dma_data_direction dir, | |
00085f1e | 179 | unsigned long attrs) |
74321d4c SD |
180 | { |
181 | void *va = phys_to_virt(page_to_phys(page)) + offset; | |
182 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
183 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
184 | ||
185 | return mic_map_single(mdev, va, size); | |
186 | } | |
187 | ||
188 | static void | |
189 | __mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | |
190 | size_t size, enum dma_data_direction dir, | |
00085f1e | 191 | unsigned long attrs) |
74321d4c SD |
192 | { |
193 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
194 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
195 | ||
196 | mic_unmap_single(mdev, dma_addr, size); | |
197 | } | |
198 | ||
199 | static int __mic_dma_map_sg(struct device *dev, struct scatterlist *sg, | |
200 | int nents, enum dma_data_direction dir, | |
00085f1e | 201 | unsigned long attrs) |
74321d4c SD |
202 | { |
203 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
204 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
205 | struct scatterlist *s; | |
206 | int i, j, ret; | |
207 | dma_addr_t da; | |
208 | ||
1da2b3ee | 209 | ret = dma_map_sg(&mdev->pdev->dev, sg, nents, dir); |
74321d4c SD |
210 | if (ret <= 0) |
211 | return 0; | |
212 | ||
213 | for_each_sg(sg, s, nents, i) { | |
214 | da = mic_map(mdev, sg_dma_address(s) + s->offset, s->length); | |
215 | if (!da) | |
216 | goto err; | |
217 | sg_dma_address(s) = da; | |
218 | } | |
219 | return nents; | |
220 | err: | |
221 | for_each_sg(sg, s, i, j) { | |
222 | mic_unmap(mdev, sg_dma_address(s), s->length); | |
223 | sg_dma_address(s) = mic_to_dma_addr(mdev, sg_dma_address(s)); | |
224 | } | |
1da2b3ee | 225 | dma_unmap_sg(&mdev->pdev->dev, sg, nents, dir); |
74321d4c SD |
226 | return 0; |
227 | } | |
228 | ||
229 | static void __mic_dma_unmap_sg(struct device *dev, | |
230 | struct scatterlist *sg, int nents, | |
231 | enum dma_data_direction dir, | |
00085f1e | 232 | unsigned long attrs) |
74321d4c SD |
233 | { |
234 | struct scif_hw_dev *scdev = dev_get_drvdata(dev); | |
235 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
236 | struct scatterlist *s; | |
237 | dma_addr_t da; | |
238 | int i; | |
239 | ||
240 | for_each_sg(sg, s, nents, i) { | |
241 | da = mic_to_dma_addr(mdev, sg_dma_address(s)); | |
242 | mic_unmap(mdev, sg_dma_address(s), s->length); | |
243 | sg_dma_address(s) = da; | |
244 | } | |
1da2b3ee | 245 | dma_unmap_sg(&mdev->pdev->dev, sg, nents, dir); |
74321d4c SD |
246 | } |
247 | ||
248 | static struct dma_map_ops __mic_dma_ops = { | |
249 | .alloc = __mic_dma_alloc, | |
250 | .free = __mic_dma_free, | |
251 | .map_page = __mic_dma_map_page, | |
252 | .unmap_page = __mic_dma_unmap_page, | |
253 | .map_sg = __mic_dma_map_sg, | |
254 | .unmap_sg = __mic_dma_unmap_sg, | |
255 | }; | |
256 | ||
257 | static struct mic_irq * | |
258 | ___mic_request_irq(struct scif_hw_dev *scdev, | |
259 | irqreturn_t (*func)(int irq, void *data), | |
260 | const char *name, | |
261 | void *data, int db) | |
262 | { | |
263 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
264 | ||
265 | return mic_request_threaded_irq(mdev, func, NULL, name, data, | |
266 | db, MIC_INTR_DB); | |
267 | } | |
268 | ||
269 | static void | |
270 | ___mic_free_irq(struct scif_hw_dev *scdev, | |
271 | struct mic_irq *cookie, void *data) | |
272 | { | |
273 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
274 | ||
fee26876 | 275 | mic_free_irq(mdev, cookie, data); |
74321d4c SD |
276 | } |
277 | ||
278 | static void ___mic_ack_interrupt(struct scif_hw_dev *scdev, int num) | |
279 | { | |
280 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
281 | ||
282 | mdev->ops->intr_workarounds(mdev); | |
283 | } | |
284 | ||
285 | static int ___mic_next_db(struct scif_hw_dev *scdev) | |
286 | { | |
287 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
288 | ||
289 | return mic_next_db(mdev); | |
290 | } | |
291 | ||
292 | static void ___mic_send_intr(struct scif_hw_dev *scdev, int db) | |
293 | { | |
294 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
295 | ||
296 | mdev->ops->send_intr(mdev, db); | |
297 | } | |
298 | ||
299 | static void __iomem *___mic_ioremap(struct scif_hw_dev *scdev, | |
300 | phys_addr_t pa, size_t len) | |
301 | { | |
302 | struct mic_device *mdev = scdev_to_mdev(scdev); | |
303 | ||
304 | return mdev->aper.va + pa; | |
305 | } | |
306 | ||
307 | static void ___mic_iounmap(struct scif_hw_dev *scdev, void __iomem *va) | |
308 | { | |
309 | /* nothing to do */ | |
310 | } | |
311 | ||
312 | static struct scif_hw_ops scif_hw_ops = { | |
313 | .request_irq = ___mic_request_irq, | |
314 | .free_irq = ___mic_free_irq, | |
315 | .ack_interrupt = ___mic_ack_interrupt, | |
316 | .next_db = ___mic_next_db, | |
317 | .send_intr = ___mic_send_intr, | |
318 | .ioremap = ___mic_ioremap, | |
319 | .iounmap = ___mic_iounmap, | |
320 | }; | |
321 | ||
d4ef098e SY |
322 | static inline struct mic_device *mbdev_to_mdev(struct mbus_device *mbdev) |
323 | { | |
324 | return dev_get_drvdata(mbdev->dev.parent); | |
325 | } | |
326 | ||
327 | static dma_addr_t | |
328 | mic_dma_map_page(struct device *dev, struct page *page, | |
329 | unsigned long offset, size_t size, enum dma_data_direction dir, | |
00085f1e | 330 | unsigned long attrs) |
d4ef098e SY |
331 | { |
332 | void *va = phys_to_virt(page_to_phys(page)) + offset; | |
333 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
334 | ||
335 | return mic_map_single(mdev, va, size); | |
336 | } | |
337 | ||
338 | static void | |
339 | mic_dma_unmap_page(struct device *dev, dma_addr_t dma_addr, | |
340 | size_t size, enum dma_data_direction dir, | |
00085f1e | 341 | unsigned long attrs) |
d4ef098e SY |
342 | { |
343 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | |
344 | mic_unmap_single(mdev, dma_addr, size); | |
345 | } | |
346 | ||
347 | static struct dma_map_ops mic_dma_ops = { | |
348 | .map_page = mic_dma_map_page, | |
349 | .unmap_page = mic_dma_unmap_page, | |
350 | }; | |
351 | ||
352 | static struct mic_irq * | |
353 | _mic_request_threaded_irq(struct mbus_device *mbdev, | |
354 | irq_handler_t handler, irq_handler_t thread_fn, | |
355 | const char *name, void *data, int intr_src) | |
356 | { | |
357 | return mic_request_threaded_irq(mbdev_to_mdev(mbdev), handler, | |
358 | thread_fn, name, data, | |
359 | intr_src, MIC_INTR_DMA); | |
360 | } | |
361 | ||
362 | static void _mic_free_irq(struct mbus_device *mbdev, | |
363 | struct mic_irq *cookie, void *data) | |
364 | { | |
fee26876 | 365 | mic_free_irq(mbdev_to_mdev(mbdev), cookie, data); |
d4ef098e SY |
366 | } |
367 | ||
368 | static void _mic_ack_interrupt(struct mbus_device *mbdev, int num) | |
369 | { | |
370 | struct mic_device *mdev = mbdev_to_mdev(mbdev); | |
371 | mdev->ops->intr_workarounds(mdev); | |
372 | } | |
373 | ||
374 | static struct mbus_hw_ops mbus_hw_ops = { | |
375 | .request_threaded_irq = _mic_request_threaded_irq, | |
376 | .free_irq = _mic_free_irq, | |
377 | .ack_interrupt = _mic_ack_interrupt, | |
378 | }; | |
379 | ||
3a6a9201 SD |
380 | /* Initialize the MIC bootparams */ |
381 | void mic_bootparam_init(struct mic_device *mdev) | |
382 | { | |
383 | struct mic_bootparam *bootparam = mdev->dp; | |
384 | ||
173c0727 | 385 | bootparam->magic = cpu_to_le32(MIC_MAGIC); |
3a6a9201 | 386 | bootparam->h2c_config_db = -1; |
74321d4c SD |
387 | bootparam->node_id = mdev->id + 1; |
388 | bootparam->scif_host_dma_addr = 0x0; | |
389 | bootparam->scif_card_dma_addr = 0x0; | |
390 | bootparam->c2h_scif_db = -1; | |
391 | bootparam->h2c_scif_db = -1; | |
392 | } | |
393 | ||
1da2b3ee AD |
394 | static inline struct mic_device *cosmdev_to_mdev(struct cosm_device *cdev) |
395 | { | |
396 | return dev_get_drvdata(cdev->dev.parent); | |
397 | } | |
398 | ||
399 | static void _mic_reset(struct cosm_device *cdev) | |
400 | { | |
401 | struct mic_device *mdev = cosmdev_to_mdev(cdev); | |
402 | ||
403 | mdev->ops->reset_fw_ready(mdev); | |
404 | mdev->ops->reset(mdev); | |
405 | } | |
406 | ||
407 | static bool _mic_ready(struct cosm_device *cdev) | |
408 | { | |
409 | struct mic_device *mdev = cosmdev_to_mdev(cdev); | |
410 | ||
411 | return mdev->ops->is_fw_ready(mdev); | |
412 | } | |
413 | ||
74321d4c SD |
414 | /** |
415 | * mic_request_dma_chans - Request DMA channels | |
416 | * @mdev: pointer to mic_device instance | |
417 | * | |
418 | * returns number of DMA channels acquired | |
419 | */ | |
420 | static int mic_request_dma_chans(struct mic_device *mdev) | |
421 | { | |
422 | dma_cap_mask_t mask; | |
423 | struct dma_chan *chan; | |
424 | ||
74321d4c SD |
425 | dma_cap_zero(mask); |
426 | dma_cap_set(DMA_MEMCPY, mask); | |
427 | ||
428 | do { | |
429 | chan = dma_request_channel(mask, mdev->ops->dma_filter, | |
1da2b3ee | 430 | &mdev->pdev->dev); |
74321d4c SD |
431 | if (chan) { |
432 | mdev->dma_ch[mdev->num_dma_ch++] = chan; | |
433 | if (mdev->num_dma_ch >= MIC_MAX_DMA_CHAN) | |
434 | break; | |
435 | } | |
436 | } while (chan); | |
1da2b3ee | 437 | dev_info(&mdev->pdev->dev, "DMA channels # %d\n", mdev->num_dma_ch); |
74321d4c SD |
438 | return mdev->num_dma_ch; |
439 | } | |
440 | ||
441 | /** | |
442 | * mic_free_dma_chans - release DMA channels | |
443 | * @mdev: pointer to mic_device instance | |
444 | * | |
445 | * returns none | |
446 | */ | |
447 | static void mic_free_dma_chans(struct mic_device *mdev) | |
448 | { | |
449 | int i = 0; | |
450 | ||
451 | for (i = 0; i < mdev->num_dma_ch; i++) { | |
452 | dma_release_channel(mdev->dma_ch[i]); | |
453 | mdev->dma_ch[i] = NULL; | |
454 | } | |
455 | mdev->num_dma_ch = 0; | |
3a6a9201 SD |
456 | } |
457 | ||
458 | /** | |
1da2b3ee AD |
459 | * _mic_start - Start the MIC. |
460 | * @cdev: pointer to cosm_device instance | |
461 | * @id: MIC device id/index provided by COSM used in other drivers like SCIF | |
3a6a9201 SD |
462 | * |
463 | * This function prepares an MIC for boot and initiates boot. | |
464 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | |
1da2b3ee AD |
465 | * |
466 | * For all cosm_hw_ops the caller holds a mutex to ensure serialization. | |
3a6a9201 | 467 | */ |
1da2b3ee | 468 | static int _mic_start(struct cosm_device *cdev, int id) |
3a6a9201 | 469 | { |
1da2b3ee | 470 | struct mic_device *mdev = cosmdev_to_mdev(cdev); |
3a6a9201 | 471 | int rc; |
1da2b3ee | 472 | |
74321d4c | 473 | mic_bootparam_init(mdev); |
1da2b3ee | 474 | mdev->dma_mbdev = mbus_register_device(&mdev->pdev->dev, |
d4ef098e | 475 | MBUS_DEV_DMA_HOST, &mic_dma_ops, |
1da2b3ee | 476 | &mbus_hw_ops, id, mdev->mmio.va); |
d4ef098e SY |
477 | if (IS_ERR(mdev->dma_mbdev)) { |
478 | rc = PTR_ERR(mdev->dma_mbdev); | |
479 | goto unlock_ret; | |
480 | } | |
74321d4c SD |
481 | if (!mic_request_dma_chans(mdev)) { |
482 | rc = -ENODEV; | |
d4ef098e SY |
483 | goto dma_remove; |
484 | } | |
1da2b3ee | 485 | mdev->scdev = scif_register_device(&mdev->pdev->dev, MIC_SCIF_DEV, |
74321d4c | 486 | &__mic_dma_ops, &scif_hw_ops, |
1da2b3ee | 487 | id + 1, 0, &mdev->mmio, |
74321d4c | 488 | &mdev->aper, mdev->dp, NULL, |
1da2b3ee AD |
489 | mdev->dma_ch, mdev->num_dma_ch, |
490 | true); | |
74321d4c SD |
491 | if (IS_ERR(mdev->scdev)) { |
492 | rc = PTR_ERR(mdev->scdev); | |
493 | goto dma_free; | |
494 | } | |
1da2b3ee | 495 | |
c74c9318 SD |
496 | mdev->vpdev = vop_register_device(&mdev->pdev->dev, |
497 | VOP_DEV_TRNSP, &_mic_dma_ops, | |
498 | &vop_hw_ops, id + 1, &mdev->aper, | |
499 | mdev->dma_ch[0]); | |
500 | if (IS_ERR(mdev->vpdev)) { | |
501 | rc = PTR_ERR(mdev->vpdev); | |
502 | goto scif_remove; | |
503 | } | |
504 | ||
1da2b3ee | 505 | rc = mdev->ops->load_mic_fw(mdev, NULL); |
3a6a9201 | 506 | if (rc) |
c74c9318 | 507 | goto vop_remove; |
3a6a9201 SD |
508 | mic_smpt_restore(mdev); |
509 | mic_intr_restore(mdev); | |
510 | mdev->intr_ops->enable_interrupts(mdev); | |
511 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | |
512 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | |
513 | mdev->ops->send_firmware_intr(mdev); | |
d4ef098e | 514 | goto unlock_ret; |
c74c9318 SD |
515 | vop_remove: |
516 | vop_unregister_device(mdev->vpdev); | |
74321d4c SD |
517 | scif_remove: |
518 | scif_unregister_device(mdev->scdev); | |
519 | dma_free: | |
520 | mic_free_dma_chans(mdev); | |
d4ef098e SY |
521 | dma_remove: |
522 | mbus_unregister_device(mdev->dma_mbdev); | |
3a6a9201 | 523 | unlock_ret: |
3a6a9201 SD |
524 | return rc; |
525 | } | |
526 | ||
527 | /** | |
1da2b3ee AD |
528 | * _mic_stop - Prepare the MIC for reset and trigger reset. |
529 | * @cdev: pointer to cosm_device instance | |
3a6a9201 SD |
530 | * @force: force a MIC to reset even if it is already offline. |
531 | * | |
532 | * RETURNS: None. | |
533 | */ | |
1da2b3ee | 534 | static void _mic_stop(struct cosm_device *cdev, bool force) |
3a6a9201 | 535 | { |
1da2b3ee | 536 | struct mic_device *mdev = cosmdev_to_mdev(cdev); |
af190494 DC |
537 | |
538 | /* | |
1da2b3ee AD |
539 | * Since SCIF handles card shutdown and reset (using COSM), it will |
540 | * will be the first to be registered and the last to be | |
541 | * unregistered. | |
af190494 | 542 | */ |
c74c9318 | 543 | vop_unregister_device(mdev->vpdev); |
1da2b3ee AD |
544 | scif_unregister_device(mdev->scdev); |
545 | mic_free_dma_chans(mdev); | |
546 | mbus_unregister_device(mdev->dma_mbdev); | |
547 | mic_bootparam_init(mdev); | |
3a6a9201 SD |
548 | } |
549 | ||
1da2b3ee | 550 | static ssize_t _mic_family(struct cosm_device *cdev, char *buf) |
3a6a9201 | 551 | { |
1da2b3ee AD |
552 | struct mic_device *mdev = cosmdev_to_mdev(cdev); |
553 | static const char *family[MIC_FAMILY_LAST] = { "x100", "Unknown" }; | |
3a6a9201 | 554 | |
1da2b3ee | 555 | return scnprintf(buf, PAGE_SIZE, "%s\n", family[mdev->family]); |
3a6a9201 | 556 | } |
af190494 | 557 | |
1da2b3ee | 558 | static ssize_t _mic_stepping(struct cosm_device *cdev, char *buf) |
af190494 | 559 | { |
1da2b3ee AD |
560 | struct mic_device *mdev = cosmdev_to_mdev(cdev); |
561 | const char *string = "??"; | |
af190494 | 562 | |
1da2b3ee AD |
563 | switch (mdev->stepping) { |
564 | case MIC_A0_STEP: | |
565 | string = "A0"; | |
af190494 | 566 | break; |
1da2b3ee AD |
567 | case MIC_B0_STEP: |
568 | string = "B0"; | |
569 | break; | |
570 | case MIC_B1_STEP: | |
571 | string = "B1"; | |
af190494 | 572 | break; |
1da2b3ee AD |
573 | case MIC_C0_STEP: |
574 | string = "C0"; | |
af190494 DC |
575 | break; |
576 | default: | |
af190494 DC |
577 | break; |
578 | } | |
1da2b3ee | 579 | return scnprintf(buf, PAGE_SIZE, "%s\n", string); |
af190494 DC |
580 | } |
581 | ||
1da2b3ee | 582 | static struct mic_mw *_mic_aper(struct cosm_device *cdev) |
af190494 | 583 | { |
1da2b3ee | 584 | struct mic_device *mdev = cosmdev_to_mdev(cdev); |
af190494 | 585 | |
1da2b3ee | 586 | return &mdev->aper; |
af190494 | 587 | } |
1da2b3ee AD |
588 | |
589 | struct cosm_hw_ops cosm_hw_ops = { | |
590 | .reset = _mic_reset, | |
591 | .force_reset = _mic_reset, | |
592 | .post_reset = NULL, | |
593 | .ready = _mic_ready, | |
594 | .start = _mic_start, | |
595 | .stop = _mic_stop, | |
596 | .family = _mic_family, | |
597 | .stepping = _mic_stepping, | |
598 | .aper = _mic_aper, | |
599 | }; |