aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic
diff options
context:
space:
mode:
authorSudeep Dutt <sudeep.dutt@intel.com>2015-04-29 08:32:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-05-24 15:13:36 -0400
commit5ec4ca6adb6abcd4479fa8d4e657748da0043f15 (patch)
tree7624f0165bebb1f7734c7166f1b80c282828f3c1 /drivers/misc/mic
parent9ad8b64820c92704326148fe9138b7ece181b440 (diff)
misc: mic: SCIF Hardware Bus
The SCIF hardware bus abstracts the low level hardware driver details like interrupts and mapping remote memory so that the same SCIF driver can work without any changes with the MIC host or card driver as long as the hardware bus operations are implemented. The SCIF hardware device is registered by the host and card drivers on the SCIF hardware bus resulting in probing the SCIF driver. Reviewed-by: Nikhil Rao <nikhil.rao@intel.com> 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/Makefile2
-rw-r--r--drivers/misc/mic/bus/Makefile1
-rw-r--r--drivers/misc/mic/bus/scif_bus.c210
-rw-r--r--drivers/misc/mic/bus/scif_bus.h129
5 files changed, 358 insertions, 1 deletions
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig
index cc4eef040c14..afc9f539b6c6 100644
--- a/drivers/misc/mic/Kconfig
+++ b/drivers/misc/mic/Kconfig
@@ -15,6 +15,23 @@ config INTEL_MIC_BUS
15 OS and tools for MIC to use with this driver are available from 15 OS and tools for MIC to use with this driver are available from
16 <http://software.intel.com/en-us/mic-developer>. 16 <http://software.intel.com/en-us/mic-developer>.
17 17
18comment "SCIF Bus Driver"
19
20config SCIF_BUS
21 tristate "SCIF Bus Driver"
22 depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS
23 help
24 This option is selected by any driver which registers a
25 device or driver on the SCIF Bus, such as CONFIG_INTEL_MIC_HOST
26 and CONFIG_INTEL_MIC_CARD.
27
28 If you are building a host/card kernel with an Intel MIC device
29 then say M (recommended) or Y, else say N. If unsure say N.
30
31 More information about the Intel MIC family as well as the Linux
32 OS and tools for MIC to use with this driver are available from
33 <http://software.intel.com/en-us/mic-developer>.
34
18comment "Intel MIC Host Driver" 35comment "Intel MIC Host Driver"
19 36
20config INTEL_MIC_HOST 37config INTEL_MIC_HOST
diff --git a/drivers/misc/mic/Makefile b/drivers/misc/mic/Makefile
index e9bf148755e2..6bc6083f5e3b 100644
--- a/drivers/misc/mic/Makefile
+++ b/drivers/misc/mic/Makefile
@@ -4,4 +4,4 @@
4# 4#
5obj-$(CONFIG_INTEL_MIC_HOST) += host/ 5obj-$(CONFIG_INTEL_MIC_HOST) += host/
6obj-$(CONFIG_INTEL_MIC_CARD) += card/ 6obj-$(CONFIG_INTEL_MIC_CARD) += card/
7obj-$(CONFIG_INTEL_MIC_BUS) += bus/ 7obj-y += bus/
diff --git a/drivers/misc/mic/bus/Makefile b/drivers/misc/mic/bus/Makefile
index d85c7f2a0af4..1ed37e234c96 100644
--- a/drivers/misc/mic/bus/Makefile
+++ b/drivers/misc/mic/bus/Makefile
@@ -3,3 +3,4 @@
3# Copyright(c) 2014, Intel Corporation. 3# Copyright(c) 2014, Intel Corporation.
4# 4#
5obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o 5obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o
6obj-$(CONFIG_SCIF_BUS) += scif_bus.o
diff --git a/drivers/misc/mic/bus/scif_bus.c b/drivers/misc/mic/bus/scif_bus.c
new file mode 100644
index 000000000000..2da7ceed015d
--- /dev/null
+++ b/drivers/misc/mic/bus/scif_bus.c
@@ -0,0 +1,210 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2014 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 * Intel Symmetric Communications Interface Bus driver.
16 */
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/idr.h>
20#include <linux/dma-mapping.h>
21
22#include "scif_bus.h"
23
24static ssize_t device_show(struct device *d,
25 struct device_attribute *attr, char *buf)
26{
27 struct scif_hw_dev *dev = dev_to_scif(d);
28
29 return sprintf(buf, "0x%04x\n", dev->id.device);
30}
31
32static DEVICE_ATTR_RO(device);
33
34static ssize_t vendor_show(struct device *d,
35 struct device_attribute *attr, char *buf)
36{
37 struct scif_hw_dev *dev = dev_to_scif(d);
38
39 return sprintf(buf, "0x%04x\n", dev->id.vendor);
40}
41
42static DEVICE_ATTR_RO(vendor);
43
44static ssize_t modalias_show(struct device *d,
45 struct device_attribute *attr, char *buf)
46{
47 struct scif_hw_dev *dev = dev_to_scif(d);
48
49 return sprintf(buf, "scif:d%08Xv%08X\n",
50 dev->id.device, dev->id.vendor);
51}
52
53static DEVICE_ATTR_RO(modalias);
54
55static struct attribute *scif_dev_attrs[] = {
56 &dev_attr_device.attr,
57 &dev_attr_vendor.attr,
58 &dev_attr_modalias.attr,
59 NULL,
60};
61ATTRIBUTE_GROUPS(scif_dev);
62
63static inline int scif_id_match(const struct scif_hw_dev *dev,
64 const struct scif_hw_dev_id *id)
65{
66 if (id->device != dev->id.device && id->device != SCIF_DEV_ANY_ID)
67 return 0;
68
69 return id->vendor == SCIF_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 scif_dev_probe().
75 */
76static int scif_dev_match(struct device *dv, struct device_driver *dr)
77{
78 unsigned int i;
79 struct scif_hw_dev *dev = dev_to_scif(dv);
80 const struct scif_hw_dev_id *ids;
81
82 ids = drv_to_scif(dr)->id_table;
83 for (i = 0; ids[i].device; i++)
84 if (scif_id_match(dev, &ids[i]))
85 return 1;
86 return 0;
87}
88
89static int scif_uevent(struct device *dv, struct kobj_uevent_env *env)
90{
91 struct scif_hw_dev *dev = dev_to_scif(dv);
92
93 return add_uevent_var(env, "MODALIAS=scif:d%08Xv%08X",
94 dev->id.device, dev->id.vendor);
95}
96
97static int scif_dev_probe(struct device *d)
98{
99 struct scif_hw_dev *dev = dev_to_scif(d);
100 struct scif_driver *drv = drv_to_scif(dev->dev.driver);
101
102 return drv->probe(dev);
103}
104
105static int scif_dev_remove(struct device *d)
106{
107 struct scif_hw_dev *dev = dev_to_scif(d);
108 struct scif_driver *drv = drv_to_scif(dev->dev.driver);
109
110 drv->remove(dev);
111 return 0;
112}
113
114static struct bus_type scif_bus = {
115 .name = "scif_bus",
116 .match = scif_dev_match,
117 .dev_groups = scif_dev_groups,
118 .uevent = scif_uevent,
119 .probe = scif_dev_probe,
120 .remove = scif_dev_remove,
121};
122
123int scif_register_driver(struct scif_driver *driver)
124{
125 driver->driver.bus = &scif_bus;
126 return driver_register(&driver->driver);
127}
128EXPORT_SYMBOL_GPL(scif_register_driver);
129
130void scif_unregister_driver(struct scif_driver *driver)
131{
132 driver_unregister(&driver->driver);
133}
134EXPORT_SYMBOL_GPL(scif_unregister_driver);
135
136static void scif_release_dev(struct device *d)
137{
138 struct scif_hw_dev *sdev = dev_to_scif(d);
139
140 kfree(sdev);
141}
142
143struct scif_hw_dev *
144scif_register_device(struct device *pdev, int id, struct dma_map_ops *dma_ops,
145 struct scif_hw_ops *hw_ops, u8 dnode, u8 snode,
146 struct mic_mw *mmio, struct mic_mw *aper, void *dp,
147 void __iomem *rdp, struct dma_chan **chan, int num_chan)
148{
149 int ret;
150 struct scif_hw_dev *sdev;
151
152 sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
153 if (!sdev)
154 return ERR_PTR(-ENOMEM);
155
156 sdev->dev.parent = pdev;
157 sdev->id.device = id;
158 sdev->id.vendor = SCIF_DEV_ANY_ID;
159 sdev->dev.archdata.dma_ops = dma_ops;
160 sdev->dev.release = scif_release_dev;
161 sdev->hw_ops = hw_ops;
162 sdev->dnode = dnode;
163 sdev->snode = snode;
164 dev_set_drvdata(&sdev->dev, sdev);
165 sdev->dev.bus = &scif_bus;
166 sdev->mmio = mmio;
167 sdev->aper = aper;
168 sdev->dp = dp;
169 sdev->rdp = rdp;
170 sdev->dev.dma_mask = &sdev->dev.coherent_dma_mask;
171 dma_set_mask(&sdev->dev, DMA_BIT_MASK(64));
172 sdev->dma_ch = chan;
173 sdev->num_dma_ch = num_chan;
174 dev_set_name(&sdev->dev, "scif-dev%u", sdev->dnode);
175 /*
176 * device_register() causes the bus infrastructure to look for a
177 * matching driver.
178 */
179 ret = device_register(&sdev->dev);
180 if (ret)
181 goto free_sdev;
182 return sdev;
183free_sdev:
184 kfree(sdev);
185 return ERR_PTR(ret);
186}
187EXPORT_SYMBOL_GPL(scif_register_device);
188
189void scif_unregister_device(struct scif_hw_dev *sdev)
190{
191 device_unregister(&sdev->dev);
192}
193EXPORT_SYMBOL_GPL(scif_unregister_device);
194
195static int __init scif_init(void)
196{
197 return bus_register(&scif_bus);
198}
199
200static void __exit scif_exit(void)
201{
202 bus_unregister(&scif_bus);
203}
204
205core_initcall(scif_init);
206module_exit(scif_exit);
207
208MODULE_AUTHOR("Intel Corporation");
209MODULE_DESCRIPTION("Intel(R) SCIF Bus driver");
210MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mic/bus/scif_bus.h b/drivers/misc/mic/bus/scif_bus.h
new file mode 100644
index 000000000000..335a228a8236
--- /dev/null
+++ b/drivers/misc/mic/bus/scif_bus.h
@@ -0,0 +1,129 @@
1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2014 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 * Intel Symmetric Communications Interface Bus driver.
16 */
17#ifndef _SCIF_BUS_H_
18#define _SCIF_BUS_H_
19/*
20 * Everything a scif driver needs to work with any particular scif
21 * hardware abstraction layer.
22 */
23#include <linux/dma-mapping.h>
24
25#include <linux/mic_common.h>
26#include "../common/mic_dev.h"
27
28struct scif_hw_dev_id {
29 u32 device;
30 u32 vendor;
31};
32
33#define MIC_SCIF_DEV 1
34#define SCIF_DEV_ANY_ID 0xffffffff
35
36/**
37 * scif_hw_dev - representation of a hardware device abstracted for scif
38 * @hw_ops: the hardware ops supported by this device
39 * @id: the device type identification (used to match it with a driver)
40 * @mmio: MMIO memory window
41 * @aper: Aperture memory window
42 * @dev: underlying device
43 * @dnode - The destination node which this device will communicate with.
44 * @snode - The source node for this device.
45 * @dp - Self device page
46 * @rdp - Remote device page
47 * @dma_ch - Array of DMA channels
48 * @num_dma_ch - Number of DMA channels available
49 */
50struct scif_hw_dev {
51 struct scif_hw_ops *hw_ops;
52 struct scif_hw_dev_id id;
53 struct mic_mw *mmio;
54 struct mic_mw *aper;
55 struct device dev;
56 u8 dnode;
57 u8 snode;
58 void *dp;
59 void __iomem *rdp;
60 struct dma_chan **dma_ch;
61 int num_dma_ch;
62};
63
64/**
65 * scif_driver - operations for a scif 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 scif_driver {
72 struct device_driver driver;
73 const struct scif_hw_dev_id *id_table;
74 int (*probe)(struct scif_hw_dev *dev);
75 void (*remove)(struct scif_hw_dev *dev);
76};
77
78/**
79 * scif_hw_ops - Hardware operations for accessing a SCIF device on the SCIF 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 * @send_intr: Send an interrupt to the remote node on a specified doorbell.
86 * @send_p2p_intr: Send an interrupt to the peer node on a specified doorbell
87 * which is specifically targeted for a peer to peer node.
88 * @ioremap: Map a buffer with the specified physical address and length.
89 * @iounmap: Unmap a buffer previously mapped.
90 */
91struct scif_hw_ops {
92 int (*next_db)(struct scif_hw_dev *sdev);
93 struct mic_irq * (*request_irq)(struct scif_hw_dev *sdev,
94 irqreturn_t (*func)(int irq,
95 void *data),
96 const char *name, void *data,
97 int db);
98 void (*free_irq)(struct scif_hw_dev *sdev,
99 struct mic_irq *cookie, void *data);
100 void (*ack_interrupt)(struct scif_hw_dev *sdev, int num);
101 void (*send_intr)(struct scif_hw_dev *sdev, int db);
102 void (*send_p2p_intr)(struct scif_hw_dev *sdev, int db,
103 struct mic_mw *mw);
104 void __iomem * (*ioremap)(struct scif_hw_dev *sdev,
105 phys_addr_t pa, size_t len);
106 void (*iounmap)(struct scif_hw_dev *sdev, void __iomem *va);
107};
108
109int scif_register_driver(struct scif_driver *driver);
110void scif_unregister_driver(struct scif_driver *driver);
111struct scif_hw_dev *
112scif_register_device(struct device *pdev, int id,
113 struct dma_map_ops *dma_ops,
114 struct scif_hw_ops *hw_ops, u8 dnode, u8 snode,
115 struct mic_mw *mmio, struct mic_mw *aper,
116 void *dp, void __iomem *rdp,
117 struct dma_chan **chan, int num_chan);
118void scif_unregister_device(struct scif_hw_dev *sdev);
119
120static inline struct scif_hw_dev *dev_to_scif(struct device *dev)
121{
122 return container_of(dev, struct scif_hw_dev, dev);
123}
124
125static inline struct scif_driver *drv_to_scif(struct device_driver *drv)
126{
127 return container_of(drv, struct scif_driver, driver);
128}
129#endif /* _SCIF_BUS_H */