aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic
diff options
context:
space:
mode:
authorSudeep Dutt <sudeep.dutt@intel.com>2016-02-08 18:48:13 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-09 20:32:37 -0500
commita19ddd6fd260d6b92de38acb1b87940045697627 (patch)
treec8fcc0a8276bdf6b53beed4d4979af850090b645 /drivers/misc/mic
parentb73c295833cc660c1acdf2601920e2abdb6a29c8 (diff)
misc: mic: MIC VOP Bus
The Virtio Over PCIe (VOP) bus abstracts the low level hardware details like interrupts and mapping remote memory so that the same VOP driver can work without changes with different MIC host or card drivers as long as the hardware bus operations are implemented. The VOP driver registers itself on the VOP bus. The base PCIe drivers implement the bus ops and register VOP devices on the bus, resulting in the VOP driver being probed with the VOP devices. This allows the VOP functionality to be shared between multiple generations of Intel MIC products. 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')
-rw-r--r--drivers/misc/mic/Kconfig17
-rw-r--r--drivers/misc/mic/bus/Makefile1
-rw-r--r--drivers/misc/mic/bus/vop_bus.c203
-rw-r--r--drivers/misc/mic/bus/vop_bus.h140
4 files changed, 361 insertions, 0 deletions
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig
index 40677df7f996..840f7ef1a141 100644
--- a/drivers/misc/mic/Kconfig
+++ b/drivers/misc/mic/Kconfig
@@ -32,6 +32,23 @@ config SCIF_BUS
32 OS and tools for MIC to use with this driver are available from 32 OS and tools for MIC to use with this driver are available from
33 <http://software.intel.com/en-us/mic-developer>. 33 <http://software.intel.com/en-us/mic-developer>.
34 34
35comment "VOP Bus Driver"
36
37config VOP_BUS
38 tristate "VOP Bus Driver"
39 depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS
40 help
41 This option is selected by any driver which registers a
42 device or driver on the VOP Bus, such as CONFIG_INTEL_MIC_HOST
43 and CONFIG_INTEL_MIC_CARD.
44
45 If you are building a host/card kernel with an Intel MIC device
46 then say M (recommended) or Y, else say N. If unsure say N.
47
48 More information about the Intel MIC family as well as the Linux
49 OS and tools for MIC to use with this driver are available from
50 <http://software.intel.com/en-us/mic-developer>.
51
35comment "Intel MIC Host Driver" 52comment "Intel MIC Host Driver"
36 53
37config INTEL_MIC_HOST 54config INTEL_MIC_HOST
diff --git a/drivers/misc/mic/bus/Makefile b/drivers/misc/mic/bus/Makefile
index 761842b0d0bb..8758a7daa52c 100644
--- a/drivers/misc/mic/bus/Makefile
+++ b/drivers/misc/mic/bus/Makefile
@@ -5,3 +5,4 @@
5obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o 5obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o
6obj-$(CONFIG_SCIF_BUS) += scif_bus.o 6obj-$(CONFIG_SCIF_BUS) += scif_bus.o
7obj-$(CONFIG_MIC_COSM) += cosm_bus.o 7obj-$(CONFIG_MIC_COSM) += cosm_bus.o
8obj-$(CONFIG_VOP_BUS) += vop_bus.o
diff --git a/drivers/misc/mic/bus/vop_bus.c b/drivers/misc/mic/bus/vop_bus.c
new file mode 100644
index 000000000000..303da222f5b6
--- /dev/null
+++ b/drivers/misc/mic/bus/vop_bus.c
@@ -0,0 +1,203 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2016 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 Virtio Over PCIe (VOP) Bus driver.
19 */
20#include <linux/slab.h>
21#include <linux/module.h>
22#include <linux/idr.h>
23#include <linux/dma-mapping.h>
24
25#include "vop_bus.h"
26
27static ssize_t device_show(struct device *d,
28 struct device_attribute *attr, char *buf)
29{
30 struct vop_device *dev = dev_to_vop(d);
31
32 return sprintf(buf, "0x%04x\n", dev->id.device);
33}
34static DEVICE_ATTR_RO(device);
35
36static ssize_t vendor_show(struct device *d,
37 struct device_attribute *attr, char *buf)
38{
39 struct vop_device *dev = dev_to_vop(d);
40
41 return sprintf(buf, "0x%04x\n", dev->id.vendor);
42}
43static DEVICE_ATTR_RO(vendor);
44
45static ssize_t modalias_show(struct device *d,
46 struct device_attribute *attr, char *buf)
47{
48 struct vop_device *dev = dev_to_vop(d);
49
50 return sprintf(buf, "vop:d%08Xv%08X\n",
51 dev->id.device, dev->id.vendor);
52}
53static DEVICE_ATTR_RO(modalias);
54
55static struct attribute *vop_dev_attrs[] = {
56 &dev_attr_device.attr,
57 &dev_attr_vendor.attr,
58 &dev_attr_modalias.attr,
59 NULL,
60};
61ATTRIBUTE_GROUPS(vop_dev);
62
63static inline int vop_id_match(const struct vop_device *dev,
64 const struct vop_device_id *id)
65{
66 if (id->device != dev->id.device && id->device != VOP_DEV_ANY_ID)
67 return 0;
68
69 return id->vendor == VOP_DEV_ANY_ID || id->vendor == dev->id.vendor;
70}
71
72/*
73 * This looks through all the IDs a driver claims to support. If any of them
74 * match, we return 1 and the kernel will call vop_dev_probe().
75 */
76static int vop_dev_match(struct device *dv, struct device_driver *dr)
77{
78 unsigned int i;
79 struct vop_device *dev = dev_to_vop(dv);
80 const struct vop_device_id *ids;
81
82 ids = drv_to_vop(dr)->id_table;
83 for (i = 0; ids[i].device; i++)
84 if (vop_id_match(dev, &ids[i]))
85 return 1;
86 return 0;
87}
88
89static int vop_uevent(struct device *dv, struct kobj_uevent_env *env)
90{
91 struct vop_device *dev = dev_to_vop(dv);
92
93 return add_uevent_var(env, "MODALIAS=vop:d%08Xv%08X",
94 dev->id.device, dev->id.vendor);
95}
96
97static int vop_dev_probe(struct device *d)
98{
99 struct vop_device *dev = dev_to_vop(d);
100 struct vop_driver *drv = drv_to_vop(dev->dev.driver);
101
102 return drv->probe(dev);
103}
104
105static int vop_dev_remove(struct device *d)
106{
107 struct vop_device *dev = dev_to_vop(d);
108 struct vop_driver *drv = drv_to_vop(dev->dev.driver);
109
110 drv->remove(dev);
111 return 0;
112}
113
114static struct bus_type vop_bus = {
115 .name = "vop_bus",
116 .match = vop_dev_match,
117 .dev_groups = vop_dev_groups,
118 .uevent = vop_uevent,
119 .probe = vop_dev_probe,
120 .remove = vop_dev_remove,
121};
122
123int vop_register_driver(struct vop_driver *driver)
124{
125 driver->driver.bus = &vop_bus;
126 return driver_register(&driver->driver);
127}
128EXPORT_SYMBOL_GPL(vop_register_driver);
129
130void vop_unregister_driver(struct vop_driver *driver)
131{
132 driver_unregister(&driver->driver);
133}
134EXPORT_SYMBOL_GPL(vop_unregister_driver);
135
136static void vop_release_dev(struct device *d)
137{
138 put_device(d);
139}
140
141struct vop_device *
142vop_register_device(struct device *pdev, int id,
143 const struct dma_map_ops *dma_ops,
144 struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
145 struct dma_chan *chan)
146{
147 int ret;
148 struct vop_device *vdev;
149
150 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
151 if (!vdev)
152 return ERR_PTR(-ENOMEM);
153
154 vdev->dev.parent = pdev;
155 vdev->id.device = id;
156 vdev->id.vendor = VOP_DEV_ANY_ID;
157 vdev->dev.archdata.dma_ops = (struct dma_map_ops *)dma_ops;
158 vdev->dev.dma_mask = &vdev->dev.coherent_dma_mask;
159 dma_set_mask(&vdev->dev, DMA_BIT_MASK(64));
160 vdev->dev.release = vop_release_dev;
161 vdev->hw_ops = hw_ops;
162 vdev->dev.bus = &vop_bus;
163 vdev->dnode = dnode;
164 vdev->aper = aper;
165 vdev->dma_ch = chan;
166 vdev->index = dnode - 1;
167 dev_set_name(&vdev->dev, "vop-dev%u", vdev->index);
168 /*
169 * device_register() causes the bus infrastructure to look for a
170 * matching driver.
171 */
172 ret = device_register(&vdev->dev);
173 if (ret)
174 goto free_vdev;
175 return vdev;
176free_vdev:
177 kfree(vdev);
178 return ERR_PTR(ret);
179}
180EXPORT_SYMBOL_GPL(vop_register_device);
181
182void vop_unregister_device(struct vop_device *dev)
183{
184 device_unregister(&dev->dev);
185}
186EXPORT_SYMBOL_GPL(vop_unregister_device);
187
188static int __init vop_init(void)
189{
190 return bus_register(&vop_bus);
191}
192
193static void __exit vop_exit(void)
194{
195 bus_unregister(&vop_bus);
196}
197
198core_initcall(vop_init);
199module_exit(vop_exit);
200
201MODULE_AUTHOR("Intel Corporation");
202MODULE_DESCRIPTION("Intel(R) VOP Bus driver");
203MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mic/bus/vop_bus.h b/drivers/misc/mic/bus/vop_bus.h
new file mode 100644
index 000000000000..fff7a865d721
--- /dev/null
+++ b/drivers/misc/mic/bus/vop_bus.h
@@ -0,0 +1,140 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2016 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 Virtio over PCIe Bus driver.
19 */
20#ifndef _VOP_BUS_H_
21#define _VOP_BUS_H_
22/*
23 * Everything a vop driver needs to work with any particular vop
24 * implementation.
25 */
26#include <linux/dmaengine.h>
27#include <linux/interrupt.h>
28
29#include "../common/mic_dev.h"
30
31struct vop_device_id {
32 u32 device;
33 u32 vendor;
34};
35
36#define VOP_DEV_TRNSP 1
37#define VOP_DEV_ANY_ID 0xffffffff
38/*
39 * Size of the internal buffer used during DMA's as an intermediate buffer
40 * for copy to/from user. Must be an integral number of pages.
41 */
42#define VOP_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL)
43
44/**
45 * vop_device - representation of a device using vop
46 * @hw_ops: the hardware ops supported by this device.
47 * @id: the device type identification (used to match it with a driver).
48 * @dev: underlying device.
49 * @dnode - The destination node which this device will communicate with.
50 * @aper: Aperture memory window
51 * @dma_ch - DMA channel
52 * @index: unique position on the vop bus
53 */
54struct vop_device {
55 struct vop_hw_ops *hw_ops;
56 struct vop_device_id id;
57 struct device dev;
58 u8 dnode;
59 struct mic_mw *aper;
60 struct dma_chan *dma_ch;
61 int index;
62};
63
64/**
65 * vop_driver - operations for a vop I/O driver
66 * @driver: underlying device driver (populate name and owner).
67 * @id_table: the ids serviced by this driver.
68 * @probe: the function to call when a device is found. Returns 0 or -errno.
69 * @remove: the function to call when a device is removed.
70 */
71struct vop_driver {
72 struct device_driver driver;
73 const struct vop_device_id *id_table;
74 int (*probe)(struct vop_device *dev);
75 void (*remove)(struct vop_device *dev);
76};
77
78/**
79 * vop_hw_ops - Hardware operations for accessing a VOP device on the VOP bus.
80 *
81 * @next_db: Obtain the next available doorbell.
82 * @request_irq: Request an interrupt on a particular doorbell.
83 * @free_irq: Free an interrupt requested previously.
84 * @ack_interrupt: acknowledge an interrupt in the ISR.
85 * @get_remote_dp: Get access to the virtio device page used by the remote
86 * node to add/remove/configure virtio devices.
87 * @get_dp: Get access to the virtio device page used by the self
88 * node to add/remove/configure virtio devices.
89 * @send_intr: Send an interrupt to the peer node on a specified doorbell.
90 * @ioremap: Map a buffer with the specified DMA address and length.
91 * @iounmap: Unmap a buffer previously mapped.
92 * @dma_filter: The DMA filter function to use for obtaining access to
93 * a DMA channel on the peer node.
94 */
95struct vop_hw_ops {
96 int (*next_db)(struct vop_device *vpdev);
97 struct mic_irq *(*request_irq)(struct vop_device *vpdev,
98 irqreturn_t (*func)(int irq, void *data),
99 const char *name, void *data,
100 int intr_src);
101 void (*free_irq)(struct vop_device *vpdev,
102 struct mic_irq *cookie, void *data);
103 void (*ack_interrupt)(struct vop_device *vpdev, int num);
104 void __iomem * (*get_remote_dp)(struct vop_device *vpdev);
105 void * (*get_dp)(struct vop_device *vpdev);
106 void (*send_intr)(struct vop_device *vpdev, int db);
107 void __iomem * (*ioremap)(struct vop_device *vpdev,
108 dma_addr_t pa, size_t len);
109 void (*iounmap)(struct vop_device *vpdev, void __iomem *va);
110};
111
112struct vop_device *
113vop_register_device(struct device *pdev, int id,
114 const struct dma_map_ops *dma_ops,
115 struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
116 struct dma_chan *chan);
117void vop_unregister_device(struct vop_device *dev);
118int vop_register_driver(struct vop_driver *drv);
119void vop_unregister_driver(struct vop_driver *drv);
120
121/*
122 * module_vop_driver() - Helper macro for drivers that don't do
123 * anything special in module init/exit. This eliminates a lot of
124 * boilerplate. Each module may only use this macro once, and
125 * calling it replaces module_init() and module_exit()
126 */
127#define module_vop_driver(__vop_driver) \
128 module_driver(__vop_driver, vop_register_driver, \
129 vop_unregister_driver)
130
131static inline struct vop_device *dev_to_vop(struct device *dev)
132{
133 return container_of(dev, struct vop_device, dev);
134}
135
136static inline struct vop_driver *drv_to_vop(struct device_driver *drv)
137{
138 return container_of(drv, struct vop_driver, driver);
139}
140#endif /* _VOP_BUS_H */