Linux Audio

Check our new training course

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