aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2013-03-27 11:29:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-29 11:35:47 -0400
commite5354107e14755991da82e0d2a4791db92908d9d (patch)
treeadb8491f5d2a37cbd9304aafb1f762fed4d6c4a5 /drivers/misc/mei
parent40e0b67be099175d069b0cf46f1102f352d46c61 (diff)
mei: bus: Initial MEI Client bus type implementation
mei client bus will present some of the mei clients as devices for other standard subsystems Implement the probe, remove, match, device addtion routines, along with the sysfs and uevent ones. mei_cl_device_id is also added to mod_devicetable.h A mei-cleint-bus.txt document describing the rationale and the API usage is also added while ABI/testing/sysfs-bus-mei describeis the modalias ABI. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r--drivers/misc/mei/Makefile1
-rw-r--r--drivers/misc/mei/bus.c172
-rw-r--r--drivers/misc/mei/mei_dev.h26
3 files changed, 199 insertions, 0 deletions
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 2c336d087749..1b29f7ccac49 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -10,6 +10,7 @@ mei-objs += client.o
10mei-objs += main.o 10mei-objs += main.o
11mei-objs += amthif.o 11mei-objs += amthif.o
12mei-objs += wd.o 12mei-objs += wd.o
13mei-objs += bus.o
13 14
14obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o 15obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
15mei-me-objs := pci-me.o 16mei-me-objs := pci-me.o
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
new file mode 100644
index 000000000000..78c876af2676
--- /dev/null
+++ b/drivers/misc/mei/bus.c
@@ -0,0 +1,172 @@
1/*
2 * Intel Management Engine Interface (Intel MEI) Linux driver
3 * Copyright (c) 2012-2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/errno.h>
21#include <linux/slab.h>
22#include <linux/mutex.h>
23#include <linux/interrupt.h>
24#include <linux/pci.h>
25#include <linux/mei_cl_bus.h>
26
27#include "mei_dev.h"
28
29#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
30#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
31
32static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
33{
34 struct mei_cl_device *device = to_mei_cl_device(dev);
35 struct mei_cl_driver *driver = to_mei_cl_driver(drv);
36 const struct mei_cl_device_id *id;
37
38 if (!device)
39 return 0;
40
41 if (!driver || !driver->id_table)
42 return 0;
43
44 id = driver->id_table;
45
46 while (id->name[0]) {
47 if (!strcmp(dev_name(dev), id->name))
48 return 1;
49
50 id++;
51 }
52
53 return 0;
54}
55
56static int mei_cl_device_probe(struct device *dev)
57{
58 struct mei_cl_device *device = to_mei_cl_device(dev);
59 struct mei_cl_driver *driver;
60 struct mei_cl_device_id id;
61
62 if (!device)
63 return 0;
64
65 driver = to_mei_cl_driver(dev->driver);
66 if (!driver || !driver->probe)
67 return -ENODEV;
68
69 dev_dbg(dev, "Device probe\n");
70
71 strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
72
73 return driver->probe(device, &id);
74}
75
76static int mei_cl_device_remove(struct device *dev)
77{
78 struct mei_cl_device *device = to_mei_cl_device(dev);
79 struct mei_cl_driver *driver;
80
81 if (!device || !dev->driver)
82 return 0;
83
84 driver = to_mei_cl_driver(dev->driver);
85 if (!driver->remove) {
86 dev->driver = NULL;
87
88 return 0;
89 }
90
91 return driver->remove(device);
92}
93
94static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
95 char *buf)
96{
97 int len;
98
99 len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));
100
101 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
102}
103
104static struct device_attribute mei_cl_dev_attrs[] = {
105 __ATTR_RO(modalias),
106 __ATTR_NULL,
107};
108
109static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
110{
111 if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
112 return -ENOMEM;
113
114 return 0;
115}
116
117static struct bus_type mei_cl_bus_type = {
118 .name = "mei",
119 .dev_attrs = mei_cl_dev_attrs,
120 .match = mei_cl_device_match,
121 .probe = mei_cl_device_probe,
122 .remove = mei_cl_device_remove,
123 .uevent = mei_cl_uevent,
124};
125
126static void mei_cl_dev_release(struct device *dev)
127{
128 kfree(to_mei_cl_device(dev));
129}
130
131static struct device_type mei_cl_device_type = {
132 .release = mei_cl_dev_release,
133};
134
135struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
136 uuid_le uuid, char *name)
137{
138 struct mei_cl_device *device;
139 int status;
140
141 device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
142 if (!device)
143 return NULL;
144
145 device->dev.parent = &mei_device->pdev->dev;
146 device->dev.bus = &mei_cl_bus_type;
147 device->dev.type = &mei_cl_device_type;
148
149 dev_set_name(&device->dev, "%s", name);
150
151 status = device_register(&device->dev);
152 if (status)
153 goto out_err;
154
155 dev_dbg(&device->dev, "client %s registered\n", name);
156
157 return device;
158
159out_err:
160 dev_err(device->dev.parent, "Failed to register MEI client\n");
161
162 kfree(device);
163
164 return NULL;
165}
166EXPORT_SYMBOL_GPL(mei_cl_add_device);
167
168void mei_cl_remove_device(struct mei_cl_device *device)
169{
170 device_unregister(&device->dev);
171}
172EXPORT_SYMBOL_GPL(mei_cl_remove_device);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index b5d66076de3d..7abb705ddf3f 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -21,6 +21,7 @@
21#include <linux/watchdog.h> 21#include <linux/watchdog.h>
22#include <linux/poll.h> 22#include <linux/poll.h>
23#include <linux/mei.h> 23#include <linux/mei.h>
24#include <linux/mei_cl_bus.h>
24 25
25#include "hw.h" 26#include "hw.h"
26#include "hw-me-regs.h" 27#include "hw-me-regs.h"
@@ -262,6 +263,31 @@ struct mei_hw_ops {
262 unsigned char *buf, unsigned long len); 263 unsigned char *buf, unsigned long len);
263}; 264};
264 265
266/* MEI bus API*/
267struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
268 uuid_le uuid, char *name);
269void mei_cl_remove_device(struct mei_cl_device *device);
270
271/**
272 * struct mei_cl_device - MEI device handle
273 * An mei_cl_device pointer is returned from mei_add_device()
274 * and links MEI bus clients to their actual ME host client pointer.
275 * Drivers for MEI devices will get an mei_cl_device pointer
276 * when being probed and shall use it for doing ME bus I/O.
277 *
278 * @dev: linux driver model device pointer
279 * @uuid: me client uuid
280 * @cl: mei client
281 * @priv_data: client private data
282 */
283struct mei_cl_device {
284 struct device dev;
285
286 struct mei_cl *cl;
287
288 void *priv_data;
289};
290
265/** 291/**
266 * struct mei_device - MEI private device struct 292 * struct mei_device - MEI private device struct
267 293