Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 * Disclaimer: The codes contained in these modules may be specific to
 19 * the Intel Software Development Platform codenamed: Knights Ferry, and
 20 * the Intel product codenamed: Knights Corner, and are not backward
 21 * compatible with other Intel products. Additionally, Intel will NOT
 22 * support the codes or instruction set in future products.
 23 *
 24 * Intel MIC Card driver.
 25 *
 26 */
 27#include <linux/module.h>
 28#include <linux/pci.h>
 29#include <linux/platform_device.h>
 30
 31#include "../common/mic_dev.h"
 32#include "mic_device.h"
 33#include "mic_x100.h"
 34
 35static const char mic_driver_name[] = "mic";
 36
 37static struct mic_driver g_drv;
 38
 39/**
 40 * mic_read_spad - read from the scratchpad register
 41 * @mdev: pointer to mic_device instance
 42 * @idx: index to scratchpad register, 0 based
 43 *
 44 * This function allows reading of the 32bit scratchpad register.
 45 *
 46 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
 47 */
 48u32 mic_read_spad(struct mic_device *mdev, unsigned int idx)
 49{
 50	return mic_mmio_read(&mdev->mmio,
 51		MIC_X100_SBOX_BASE_ADDRESS +
 52		MIC_X100_SBOX_SPAD0 + idx * 4);
 53}
 54
 55/**
 56 * __mic_send_intr - Send interrupt to Host.
 57 * @mdev: pointer to mic_device instance
 58 * @doorbell: Doorbell number.
 59 */
 60void mic_send_intr(struct mic_device *mdev, int doorbell)
 61{
 62	struct mic_mw *mw = &mdev->mmio;
 63
 64	if (doorbell > MIC_X100_MAX_DOORBELL_IDX)
 65		return;
 66	/* Ensure that the interrupt is ordered w.r.t previous stores. */
 67	wmb();
 68	mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT,
 69		       MIC_X100_SBOX_BASE_ADDRESS +
 70		       (MIC_X100_SBOX_SDBIC0 + (4 * doorbell)));
 71}
 72
 73/*
 74 * mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC.
 75 */
 76static void mic_x100_send_sbox_intr(struct mic_mw *mw, int doorbell)
 77{
 78	u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8;
 79	u32 apicicr_low = mic_mmio_read(mw, MIC_X100_SBOX_BASE_ADDRESS +
 80					apic_icr_offset);
 81
 82	/* for MIC we need to make sure we "hit" the send_icr bit (13) */
 83	apicicr_low = (apicicr_low | (1 << 13));
 84	/*
 85	 * Ensure that the interrupt is ordered w.r.t. previous stores
 86	 * to main memory. Fence instructions are not implemented in X100
 87	 * since execution is in order but a compiler barrier is still
 88	 * required.
 89	 */
 90	wmb();
 91	mic_mmio_write(mw, apicicr_low,
 92		       MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset);
 93}
 94
 95static void mic_x100_send_rdmasr_intr(struct mic_mw *mw, int doorbell)
 96{
 97	int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2);
 98	/*
 99	 * Ensure that the interrupt is ordered w.r.t. previous stores
100	 * to main memory. Fence instructions are not implemented in X100
101	 * since execution is in order but a compiler barrier is still
102	 * required.
103	 */
104	wmb();
105	mic_mmio_write(mw, 0, MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset);
106}
107
108/**
109 * mic_ack_interrupt - Device specific interrupt handling.
110 * @mdev: pointer to mic_device instance
111 *
112 * Returns: bitmask of doorbell events triggered.
113 */
114u32 mic_ack_interrupt(struct mic_device *mdev)
115{
116	return 0;
117}
118
119static inline int mic_get_sbox_irq(int db)
120{
121	return MIC_X100_IRQ_BASE + db;
122}
123
124static inline int mic_get_rdmasr_irq(int index)
125{
126	return  MIC_X100_RDMASR_IRQ_BASE + index;
127}
128
129void mic_send_p2p_intr(int db, struct mic_mw *mw)
130{
131	int rdmasr_index;
132
133	if (db < MIC_X100_NUM_SBOX_IRQ) {
134		mic_x100_send_sbox_intr(mw, db);
135	} else {
136		rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
137		mic_x100_send_rdmasr_intr(mw, rdmasr_index);
138	}
139}
140
141/**
142 * mic_hw_intr_init - Initialize h/w specific interrupt
143 * information.
144 * @mdrv: pointer to mic_driver
145 */
146void mic_hw_intr_init(struct mic_driver *mdrv)
147{
148	mdrv->intr_info.num_intr = MIC_X100_NUM_SBOX_IRQ +
149				MIC_X100_NUM_RDMASR_IRQ;
150}
151
152/**
153 * mic_db_to_irq - Retrieve irq number corresponding to a doorbell.
154 * @mdrv: pointer to mic_driver
155 * @db: The doorbell obtained for which the irq is needed. Doorbell
156 * may correspond to an sbox doorbell or an rdmasr index.
157 *
158 * Returns the irq corresponding to the doorbell.
159 */
160int mic_db_to_irq(struct mic_driver *mdrv, int db)
161{
162	int rdmasr_index;
163
164	/*
165	 * The total number of doorbell interrupts on the card are 16. Indices
166	 * 0-8 falls in the SBOX category and 8-15 fall in the RDMASR category.
167	 */
168	if (db < MIC_X100_NUM_SBOX_IRQ) {
169		return mic_get_sbox_irq(db);
170	} else {
171		rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
172		return mic_get_rdmasr_irq(rdmasr_index);
173	}
174}
175
176/*
177 * mic_card_map - Allocate virtual address for a remote memory region.
178 * @mdev: pointer to mic_device instance.
179 * @addr: Remote DMA address.
180 * @size: Size of the region.
181 *
182 * Returns: Virtual address backing the remote memory region.
183 */
184void __iomem *
185mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size)
186{
187	return ioremap(addr, size);
188}
189
190/*
191 * mic_card_unmap - Unmap the virtual address for a remote memory region.
192 * @mdev: pointer to mic_device instance.
193 * @addr: Virtual address for remote memory region.
194 *
195 * Returns: None.
196 */
197void mic_card_unmap(struct mic_device *mdev, void __iomem *addr)
198{
199	iounmap(addr);
200}
201
202static inline struct mic_driver *mbdev_to_mdrv(struct mbus_device *mbdev)
203{
204	return dev_get_drvdata(mbdev->dev.parent);
205}
206
207static struct mic_irq *
208_mic_request_threaded_irq(struct mbus_device *mbdev,
209			  irq_handler_t handler, irq_handler_t thread_fn,
210			  const char *name, void *data, int intr_src)
211{
212	int rc = 0;
213	unsigned int irq = intr_src;
214	unsigned long cookie = irq;
215
216	rc  = request_threaded_irq(irq, handler, thread_fn, 0, name, data);
217	if (rc) {
218		dev_err(mbdev_to_mdrv(mbdev)->dev,
219			"request_threaded_irq failed rc = %d\n", rc);
220		return ERR_PTR(rc);
221	}
222	return (struct mic_irq *)cookie;
223}
224
225static void _mic_free_irq(struct mbus_device *mbdev,
226			  struct mic_irq *cookie, void *data)
227{
228	unsigned long irq = (unsigned long)cookie;
229	free_irq(irq, data);
230}
231
232static void _mic_ack_interrupt(struct mbus_device *mbdev, int num)
233{
234	mic_ack_interrupt(&mbdev_to_mdrv(mbdev)->mdev);
235}
236
237static struct mbus_hw_ops mbus_hw_ops = {
238	.request_threaded_irq = _mic_request_threaded_irq,
239	.free_irq = _mic_free_irq,
240	.ack_interrupt = _mic_ack_interrupt,
241};
242
243static int __init mic_probe(struct platform_device *pdev)
244{
245	struct mic_driver *mdrv = &g_drv;
246	struct mic_device *mdev = &mdrv->mdev;
247	int rc = 0;
248
249	mdrv->dev = &pdev->dev;
250	snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name);
251
252	mdev->mmio.pa = MIC_X100_MMIO_BASE;
253	mdev->mmio.len = MIC_X100_MMIO_LEN;
254	mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE,
255				     MIC_X100_MMIO_LEN);
256	if (!mdev->mmio.va) {
257		dev_err(&pdev->dev, "Cannot remap MMIO BAR\n");
258		rc = -EIO;
259		goto done;
260	}
261	mic_hw_intr_init(mdrv);
262	platform_set_drvdata(pdev, mdrv);
263	mdrv->dma_mbdev = mbus_register_device(mdrv->dev, MBUS_DEV_DMA_MIC,
264					       NULL, &mbus_hw_ops, 0,
265					       mdrv->mdev.mmio.va);
266	if (IS_ERR(mdrv->dma_mbdev)) {
267		rc = PTR_ERR(mdrv->dma_mbdev);
268		dev_err(&pdev->dev, "mbus_add_device failed rc %d\n", rc);
269		goto done;
270	}
271	rc = mic_driver_init(mdrv);
272	if (rc) {
273		dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc);
274		goto remove_dma;
275	}
276done:
277	return rc;
278remove_dma:
279	mbus_unregister_device(mdrv->dma_mbdev);
280	return rc;
281}
282
283static int mic_remove(struct platform_device *pdev)
284{
285	struct mic_driver *mdrv = &g_drv;
286
287	mic_driver_uninit(mdrv);
288	mbus_unregister_device(mdrv->dma_mbdev);
289	return 0;
290}
291
292static void mic_platform_shutdown(struct platform_device *pdev)
293{
294	mic_remove(pdev);
295}
296
297static u64 mic_dma_mask = DMA_BIT_MASK(64);
298
299static struct platform_device mic_platform_dev = {
300	.name = mic_driver_name,
301	.id   = 0,
302	.num_resources = 0,
303	.dev = {
304		.dma_mask = &mic_dma_mask,
305		.coherent_dma_mask = DMA_BIT_MASK(64),
306	},
307};
308
309static struct platform_driver __refdata mic_platform_driver = {
310	.probe = mic_probe,
311	.remove = mic_remove,
312	.shutdown = mic_platform_shutdown,
313	.driver         = {
314		.name   = mic_driver_name,
315	},
316};
317
318static int __init mic_init(void)
319{
320	int ret;
321	struct cpuinfo_x86 *c = &cpu_data(0);
322
323	if (!(c->x86 == 11 && c->x86_model == 1)) {
324		ret = -ENODEV;
325		pr_err("%s not running on X100 ret %d\n", __func__, ret);
326		goto done;
327	}
328
329	request_module("mic_x100_dma");
330	mic_init_card_debugfs();
331	ret = platform_device_register(&mic_platform_dev);
332	if (ret) {
333		pr_err("platform_device_register ret %d\n", ret);
334		goto cleanup_debugfs;
335	}
336	ret = platform_driver_register(&mic_platform_driver);
337	if (ret) {
338		pr_err("platform_driver_register ret %d\n", ret);
339		goto device_unregister;
340	}
341	return ret;
342
343device_unregister:
344	platform_device_unregister(&mic_platform_dev);
345cleanup_debugfs:
346	mic_exit_card_debugfs();
347done:
348	return ret;
349}
350
351static void __exit mic_exit(void)
352{
353	platform_driver_unregister(&mic_platform_driver);
354	platform_device_unregister(&mic_platform_dev);
355	mic_exit_card_debugfs();
356}
357
358module_init(mic_init);
359module_exit(mic_exit);
360
361MODULE_AUTHOR("Intel Corporation");
362MODULE_DESCRIPTION("Intel(R) MIC X100 Card driver");
363MODULE_LICENSE("GPL v2");