Linux Audio

Check our new training course

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