All of lore.kernel.org
 help / color / mirror / Atom feed
* [char-misc-next 00/11 V4] Add Client MEI bus and NFC device
@ 2013-03-20 22:44 Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation Tomas Winkler
                   ` (10 more replies)
  0 siblings, 11 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

This is take 4 on the MEI bus + NFC device patches

This patch set adds implementation of MEI CLIENT BUS abstraction
over MEI device, this allows standard Linux device drivers
to access functionality exposed by MEI device clients that was previously
available only to the user space through /dev/mei

The first exercises is to export the NFC radio

More information can be found under

Documentation/misc-devices/mei/mei-client-bus.txt

v3 -> v4:
	The bus is named mei client bus
- Renames:
        * mei_bus_driver to mei_cl_driver
        * mei_bus_device to mei_cl_device
v2 -> v3:
- Renames:
        * mei_device to mei_host. The mei_host pointers are still called *dev
          as I didn't want the first patch to get too fat. 
        * mei_bus_driver to mei_driver
        * mei_bus_client to mei_device

- mei_driver structure changes:
	* name pointer addition
	* MEI id table
	* probe routine now takes the probed MEI id as an argument

- mei-bus.txt update according to the mei_driver changes and the structure
  renaming.
- All exported symbols converted to EXPORT_SYMBOL_GPL.
- to_mei_* macros moved to bus.c
- drivers/misc/mei/bus.h deleted, all API definitions moved to mei_dev.h
- mei_device structure clenup: mei_host, mei_driver, and name fields removed.
- Fixed driver owner: mei_driver_register() is now a macro over
  __mei_driver_register, using THIS_MODULE as the default owner.

Samuel Ortiz (11):
  mei: bus: Initial MEI Client bus type implementation
  mei: bus: Implement driver registration
  mei: bus: Initial implementation for I/O routines
  mei: bus: Add bus related structures to mei_cl
  mei: bus: Call bus routines from the core code
  mei: bus: Synchronous API for the data transmission
  mei: bus: Implement bus driver data setter/getter
  mei: nfc: Initial nfc implementation
  mei: nfc: Connect also the regular ME client
  mei: nfc: Add NFC device to the MEI bus
  mei: nfc: Implement MEI bus IO ops

 Documentation/misc-devices/mei/mei-client-bus.txt | 143 +++++++
 drivers/misc/mei/Kconfig                          |   7 +
 drivers/misc/mei/Makefile                         |   2 +
 drivers/misc/mei/bus.c                            | 474 ++++++++++++++++++++++
 drivers/misc/mei/client.c                         |   4 +
 drivers/misc/mei/init.c                           |   3 +
 drivers/misc/mei/interrupt.c                      |   2 +
 drivers/misc/mei/mei_dev.h                        | 100 ++++-
 drivers/misc/mei/nfc.c                            | 458 +++++++++++++++++++++
 drivers/misc/mei/nfc.h                            | 141 +++++++
 drivers/misc/mei/pci-me.c                         |  21 +-
 include/linux/mei_cl_bus.h                        | 113 ++++++
 12 files changed, 1465 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
 create mode 100644 drivers/misc/mei/bus.c
 create mode 100644 drivers/misc/mei/nfc.c
 create mode 100644 drivers/misc/mei/nfc.h
 create mode 100644 include/linux/mei_cl_bus.h

-- 
1.8.1.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-25 20:28   ` Greg KH
  2013-03-20 22:44 ` [char-misc-next 02/11 V4] mei: bus: Implement driver registration Tomas Winkler
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

mei cleint bus will present some of the me clients
as devices for other standard subsystems

Implement the probe, remove, match and the device addtion routines.
A mei-cleint-bus.txt document describing the rationale and the API usage
is also added.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 Documentation/misc-devices/mei/mei-client-bus.txt | 143 ++++++++++++++++++++
 drivers/misc/mei/Makefile                         |   1 +
 drivers/misc/mei/bus.c                            | 151 ++++++++++++++++++++++
 drivers/misc/mei/mei_dev.h                        |  27 ++++
 include/linux/mei_cl_bus.h                        |  92 +++++++++++++
 5 files changed, 414 insertions(+)
 create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
 create mode 100644 drivers/misc/mei/bus.c
 create mode 100644 include/linux/mei_cl_bus.h

diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
new file mode 100644
index 0000000..5fb2fa3
--- /dev/null
+++ b/Documentation/misc-devices/mei/mei-client-bus.txt
@@ -0,0 +1,143 @@
+Intel(R) Management Engine (ME) Client bus API
+===============================================
+
+
+Rationale
+=========
+MEI misc character device is useful for dedicated applications to send and receive
+data to the many FW appliance found in Intel's ME from the user space.
+However for some of the ME functionalities it make sense to leverage existing software
+stack and expose them through existing kernel subsystems.
+
+In order to plug seamlessly into the kernel device driver model we add kernel virtual
+bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers
+for the various MEI features as a stand alone entities found in their respective subsystem.
+Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
+the existing code.
+
+
+MEI CL bus API
+===========
+A driver implementation for an MEI Client is very similar to existing bus
+based device drivers. The driver registers itself as an MEI CL bus driver through
+the mei_cl_driver structure:
+
+struct mei_cl_driver {
+	struct device_driver driver;
+	const char *name;
+
+	const struct mei_cl_id *id_table;
+
+	int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
+	int (*remove)(struct mei_cl_device *dev);
+};
+
+struct mei_cl_id {
+	char name[MEI_NAME_SIZE];
+	uuid_le uuid;
+};
+
+The mei_cl_id structure allows the driver to bind itself against an ME UUID and a
+device name.  There is typically one ME UUID per technology and the mei_cl_id name
+field matches a specific implementation of that technology. As an example,
+the ME supports NFC devices from multiple IP vendors and device types.
+All of them have the same ME UUID but the ME bus code will assign
+each of them a different name. There is some analogy to device class and device
+vendor terms.
+
+To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
+API. This is typically called at module init time.
+
+Once registered on the ME Client bus, a driver will typically try to do some I/O on
+this bus and this should be done through the mei_cl_send() and mei_cl_recv()
+routines. The latter is synchronous (blocks and sleeps until data shows up).
+In order for drivers to be notified of pending events waiting for them (e.g.
+an Rx event) they can register an event handler through the
+mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
+will trigger an event handler call and the driver implementation is supposed
+to call mei_recv() from the event handler in order to fetch the pending
+received buffers.
+
+
+Example
+=======
+As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
+The driver init and exit routines for this device would look like:
+
+#define CONTACT_DRIVER_NAME "contact"
+
+#define NFC_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
+			       0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
+
+static struct mei_cl_id contact_mei_cl_tbl[] = {
+	{ CONTACT_DRIVER_NAME, NFC_UUID },
+
+	/* required last entry */
+	{ }
+};
+
+static struct mei_cl_driver contact_driver = {
+       .id_table = contact_mei_tbl,
+       .name = CONTACT_DRIVER_NAME,
+
+       .probe = contact_probe,
+       .remove = contact_remove,
+};
+
+static int contact_init(void)
+{
+	int r;
+
+	r = mei_cl_driver_register(&contact_driver);
+	if (r) {
+		pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void __exit contact_exit(void)
+{
+	mei_cl_driver_unregister(&contact_driver);
+}
+
+module_init(contact_init);
+module_exit(contact_exit);
+
+And the driver's simplified probe routine would look like that:
+
+int contact_probe(struct mei_cl_device *dev, struct mei_cl_id *id)
+{
+	struct contact_driver *contact;
+
+	[...]
+	mei_cl_register_event_cb(dev, contact_event_cb, contact);
+
+	return 0;
+ }
+
+In the probe routine the driver basically registers an ME bus event handler
+which is as close as it can get to registering a threaded IRQ handler.
+The handler implementation will typically call some I/O routine depending on
+the pending events:
+
+#define MAX_NFC_PAYLOAD 128
+
+static void contact_event_cb(struct mei_cl_device *dev, u32 events,
+			     void *context)
+{
+	struct contact_driver *contact = context;
+
+	if (events & BIT(MEI_EVENT_RX)) {
+		u8 payload[MAX_NFC_PAYLOAD];
+		int payload_size;
+
+		payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
+		if (payload_size <= 0)
+			return;
+
+		/* Hook to the NFC subsystem */
+		nfc_hci_recv_frame(contact->hdev, payload, payload_size);
+	}
+}
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 040af6c..5948621 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -10,5 +10,6 @@ mei-objs += client.o
 mei-objs += main.o
 mei-objs += amthif.o
 mei-objs += wd.o
+mei-objs += bus.o
 mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
 mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
new file mode 100644
index 0000000..24a25db
--- /dev/null
+++ b/drivers/misc/mei/bus.c
@@ -0,0 +1,151 @@
+/*
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+
+#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
+#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
+
+static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
+{
+	struct mei_cl_device *device = to_mei_cl_device(dev);
+	struct mei_cl_driver *driver = to_mei_cl_driver(drv);
+	const struct mei_cl_id *id;
+
+	if (!device)
+		return 0;
+
+	if (!driver || !driver->id_table)
+		return 0;
+
+	id = driver->id_table;
+
+	while (id->name[0]) {
+		if (!uuid_le_cmp(device->uuid, id->uuid) &&
+		    !strcmp(dev_name(dev), id->name))
+			return 1;
+
+		id++;
+	}
+
+	return 0;
+}
+
+static int mei_cl_device_probe(struct device *dev)
+{
+	struct mei_cl_device *device = to_mei_cl_device(dev);
+	struct mei_cl_driver *driver;
+	struct mei_cl_id id;
+
+	if (!device)
+		return 0;
+
+	driver = to_mei_cl_driver(dev->driver);
+	if (!driver || !driver->probe)
+		return -ENODEV;
+
+	dev_dbg(dev, "Device probe\n");
+
+	id.uuid = device->uuid;
+	strncpy(id.name, dev_name(dev), MEI_NAME_SIZE);
+
+	return driver->probe(device, &id);
+}
+
+static int mei_cl_device_remove(struct device *dev)
+{
+	struct mei_cl_device *device = to_mei_cl_device(dev);
+	struct mei_cl_driver *driver;
+
+	if (!device || !dev->driver)
+		return 0;
+
+	driver = to_mei_cl_driver(dev->driver);
+	if (!driver->remove) {
+		dev->driver = NULL;
+
+		return 0;
+	}
+
+	return driver->remove(device);
+}
+
+static struct bus_type mei_cl_bus_type = {
+	.name		= "mei",
+	.match		= mei_cl_device_match,
+	.probe		= mei_cl_device_probe,
+	.remove		= mei_cl_device_remove,
+};
+
+static void mei_cl_dev_release(struct device *dev)
+{
+	kfree(to_mei_cl_device(dev));
+}
+
+static struct device_type mei_cl_device_type = {
+	.release	= mei_cl_dev_release,
+};
+
+struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
+				  uuid_le uuid, char *name)
+{
+	struct mei_cl_device *device;
+	int status;
+
+	device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
+	if (!device)
+		return NULL;
+
+	device->uuid = uuid;
+
+	device->dev.parent = &mei_device->pdev->dev;
+	device->dev.bus = &mei_cl_bus_type;
+	device->dev.type = &mei_cl_device_type;
+
+	dev_set_name(&device->dev, "%s", name);
+
+	status = device_register(&device->dev);
+	if (status)
+		goto out_err;
+
+	dev_dbg(&device->dev, "client %s registered\n", name);
+
+	return device;
+
+out_err:
+	dev_err(device->dev.parent, "Failed to register MEI client\n");
+
+	kfree(device);
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(mei_cl_add_device);
+
+void mei_cl_remove_device(struct mei_cl_device *device)
+{
+	device_unregister(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_remove_device);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 091f50af..db8245e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -21,6 +21,7 @@
 #include <linux/watchdog.h>
 #include <linux/poll.h>
 #include <linux/mei.h>
+#include <linux/mei_cl_bus.h>
 
 #include "hw.h"
 #include "hw-me-regs.h"
@@ -262,6 +263,32 @@ struct mei_hw_ops {
 		     unsigned char *buf, unsigned long len);
 };
 
+/* MEI bus API*/
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+				  uuid_le uuid, char *name);
+void mei_cl_remove_device(struct mei_cl_device *device);
+
+/**
+ * struct mei_cl_device - MEI device handle
+ * An mei_cl_device pointer is returned from mei_add_device()
+ * and links MEI bus clients to their actual ME host client pointer.
+ * Drivers for MEI devices will get an mei_cl_device pointer
+ * when being probed and shall use it for doing ME bus I/O.
+ *
+ * @dev: linux driver model device pointer
+ * @uuid: me client uuid
+ * @cl: mei client
+ * @priv_data: client private data
+ */
+struct mei_cl_device {
+	struct device dev;
+
+	uuid_le uuid;
+	struct mei_cl *cl;
+
+	void *priv_data;
+};
+
 /**
  * struct mei_device -  MEI private device struct
 
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
new file mode 100644
index 0000000..ed4199b
--- /dev/null
+++ b/include/linux/mei_cl_bus.h
@@ -0,0 +1,92 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *	Intel Corporation.
+ *	linux-mei@linux.intel.com
+ *	http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef _LINUX_MEI_CL_BUS_H
+#define _LINUX_MEI_CL_BUS_H
+
+#include <linux/device.h>
+#include <linux/uuid.h>
+
+struct mei_cl_device;
+
+#define MEI_NAME_SIZE 32
+
+struct mei_cl_id {
+	char name[MEI_NAME_SIZE];
+	uuid_le uuid;
+};
+
+struct mei_cl_driver {
+	struct device_driver driver;
+	const char *name;
+
+	const struct mei_cl_id *id_table;
+
+	int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
+	int (*remove)(struct mei_cl_device *dev);
+};
+
+#endif /* _LINUX_MEI_CL_BUS_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 02/11 V4] mei: bus: Implement driver registration
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 03/11 V4] mei: bus: Initial implementation for I/O routines Tomas Winkler
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 26 ++++++++++++++++++++++++++
 include/linux/mei_cl_bus.h |  7 +++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 24a25db..9283dd6 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -149,3 +149,29 @@ void mei_cl_remove_device(struct mei_cl_device *device)
 	device_unregister(&device->dev);
 }
 EXPORT_SYMBOL_GPL(mei_cl_remove_device);
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
+{
+	int err;
+
+	driver->driver.name = driver->name;
+	driver->driver.owner = owner;
+	driver->driver.bus = &mei_cl_bus_type;
+
+	err = driver_register(&driver->driver);
+	if (err)
+		return err;
+
+	pr_debug("mei: driver [%s] registered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver)
+{
+	driver_unregister(&driver->driver);
+
+	pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index ed4199b..92c30a8 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -89,4 +89,11 @@ struct mei_cl_driver {
 	int (*remove)(struct mei_cl_device *dev);
 };
 
+int __mei_cl_driver_register(struct mei_cl_driver *driver,
+				struct module *owner);
+#define mei_cl_driver_register(driver)             \
+	__mei_cl_driver_register(driver, THIS_MODULE)
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver);
+
 #endif /* _LINUX_MEI_CL_BUS_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 03/11 V4] mei: bus: Initial implementation for I/O routines
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 02/11 V4] mei: bus: Implement driver registration Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 04/11 V4] mei: bus: Add bus related structures to mei_cl Tomas Winkler
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 226 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/mei_dev.h |  30 ++++++
 include/linux/mei_cl_bus.h |  11 +++
 3 files changed, 267 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 9283dd6..43f77b8 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
@@ -25,6 +26,8 @@
 #include <linux/mei_cl_bus.h>
 
 #include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
 
 #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
 #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
@@ -83,6 +86,11 @@ static int mei_cl_device_remove(struct device *dev)
 	if (!device || !dev->driver)
 		return 0;
 
+	if (device->event_cb) {
+		device->event_cb = NULL;
+		cancel_work_sync(&device->event_work);
+	}
+
 	driver = to_mei_cl_driver(dev->driver);
 	if (!driver->remove) {
 		dev->driver = NULL;
@@ -175,3 +183,221 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
 	pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
 }
 EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
+
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+	struct mei_device *dev;
+	struct mei_msg_hdr mei_hdr;
+	struct mei_cl_cb *cb;
+	int me_cl_id, err;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	if (cl->state != MEI_FILE_CONNECTED)
+		return -ENODEV;
+
+	cb = mei_io_cb_init(cl, NULL);
+	if (!cb)
+		return -ENOMEM;
+
+	err = mei_io_cb_alloc_req_buf(cb, length);
+	if (err < 0) {
+		mei_io_cb_free(cb);
+		return err;
+	}
+
+	memcpy(cb->request_buffer.data, buf, length);
+	cb->fop_type = MEI_FOP_WRITE;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+
+	/* Check if we have an ME client device */
+	me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id);
+	if (me_cl_id == dev->me_clients_num) {
+		err = -ENODEV;
+		goto out_err;
+	}
+
+	if (length > dev->me_clients[me_cl_id].props.max_msg_length) {
+		err = -EINVAL;
+		goto out_err;
+	}
+
+	err = mei_cl_flow_ctrl_creds(cl);
+	if (err < 0)
+		goto out_err;
+
+	/* Host buffer is not ready, we queue the request */
+	if (err == 0 || !dev->hbuf_is_ready) {
+		cb->buf_idx = 0;
+		mei_hdr.msg_complete = 0;
+		cl->writing_state = MEI_WRITING;
+		list_add_tail(&cb->list, &dev->write_list.list);
+
+		mutex_unlock(&dev->device_lock);
+
+		return length;
+	}
+
+	dev->hbuf_is_ready = false;
+
+	/* Check for a maximum length */
+	if (length > mei_hbuf_max_len(dev)) {
+		mei_hdr.length = mei_hbuf_max_len(dev);
+		mei_hdr.msg_complete = 0;
+	} else {
+		mei_hdr.length = length;
+		mei_hdr.msg_complete = 1;
+	}
+
+	mei_hdr.host_addr = cl->host_client_id;
+	mei_hdr.me_addr = cl->me_client_id;
+	mei_hdr.reserved = 0;
+
+	if (mei_write_message(dev, &mei_hdr, buf)) {
+		err = -EIO;
+		goto out_err;
+	}
+
+	cl->writing_state = MEI_WRITING;
+	cb->buf_idx = mei_hdr.length;
+
+	if (!mei_hdr.msg_complete) {
+		list_add_tail(&cb->list, &dev->write_list.list);
+	} else {
+		if (mei_cl_flow_ctrl_reduce(cl)) {
+			err = -EIO;
+			goto out_err;
+		}
+
+		list_add_tail(&cb->list, &dev->write_waiting_list.list);
+	}
+
+	mutex_unlock(&dev->device_lock);
+
+	return mei_hdr.length;
+
+out_err:
+	mutex_unlock(&dev->device_lock);
+	mei_io_cb_free(cb);
+
+	return err;
+}
+
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+{
+	struct mei_device *dev;
+	struct mei_cl_cb *cb;
+	size_t r_length;
+	int err;
+
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
+
+	dev = cl->dev;
+
+	mutex_lock(&dev->device_lock);
+
+	if (!cl->read_cb) {
+		err = mei_cl_read_start(cl);
+		if (err < 0) {
+			mutex_unlock(&dev->device_lock);
+			return err;
+		}
+	}
+
+	if (cl->reading_state != MEI_READ_COMPLETE &&
+	    !waitqueue_active(&cl->rx_wait)) {
+		mutex_unlock(&dev->device_lock);
+
+		if (wait_event_interruptible(cl->rx_wait,
+				(MEI_READ_COMPLETE == cl->reading_state))) {
+			if (signal_pending(current))
+				return -EINTR;
+			return -ERESTARTSYS;
+		}
+
+		mutex_lock(&dev->device_lock);
+	}
+
+	cb = cl->read_cb;
+
+	if (cl->reading_state != MEI_READ_COMPLETE) {
+		r_length = 0;
+		goto out;
+	}
+
+	r_length = min_t(size_t, length, cb->buf_idx);
+
+	memcpy(buf, cb->response_buffer.data, r_length);
+
+	mei_io_cb_free(cb);
+	cl->reading_state = MEI_IDLE;
+	cl->read_cb = NULL;
+
+out:
+	mutex_unlock(&dev->device_lock);
+
+	return r_length;
+}
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+	struct mei_cl *cl = NULL;
+
+	/* TODO: hook between mei_bus_client and mei_cl */
+
+	if (device->ops && device->ops->send)
+		return device->ops->send(device, buf, length);
+
+	return __mei_cl_send(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_send);
+
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+	struct mei_cl *cl = NULL;
+
+	/* TODO: hook between mei_bus_client and mei_cl */
+
+	if (device->ops && device->ops->recv)
+		return device->ops->recv(device, buf, length);
+
+	return __mei_cl_recv(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_recv);
+
+static void mei_bus_event_work(struct work_struct *work)
+{
+	struct mei_cl_device *device;
+
+	device = container_of(work, struct mei_cl_device, event_work);
+
+	if (device->event_cb)
+		device->event_cb(device, device->events, device->event_context);
+
+	device->events = 0;
+
+	/* Prepare for the next read */
+	mei_cl_read_start(device->cl);
+}
+
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+			  mei_cl_event_cb_t event_cb, void *context)
+{
+	if (device->event_cb)
+		return -EALREADY;
+
+	device->events = 0;
+	device->event_cb = event_cb;
+	device->event_context = context;
+	INIT_WORK(&device->event_work, mei_bus_event_work);
+
+	mei_cl_read_start(device->cl);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index db8245e..800ac2b 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -268,6 +268,25 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
 				  uuid_le uuid, char *name);
 void mei_cl_remove_device(struct mei_cl_device *device);
 
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+
+/**
+ * struct mei_cl_transport_ops - MEI CL device transport ops
+ * This structure allows ME host clients to implement technology
+ * specific transport layers.
+ *
+ * @send: Tx hook for the device. This allows ME host clients to trap
+ *	the device driver buffers before actually physically
+ *	pushing it to the ME.
+ * @recv: Rx hook for the device. This allows ME host clients to trap the
+ *	ME buffers before forwarding them to the device driver.
+ */
+struct mei_cl_transport_ops {
+	int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
+	int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
+};
+
 /**
  * struct mei_cl_device - MEI device handle
  * An mei_cl_device pointer is returned from mei_add_device()
@@ -278,6 +297,10 @@ void mei_cl_remove_device(struct mei_cl_device *device);
  * @dev: linux driver model device pointer
  * @uuid: me client uuid
  * @cl: mei client
+ * @ops: ME transport ops
+ * @event_cb: Drivers register this callback to get asynchronous ME
+ *	events (e.g. Rx buffer pending) notifications.
+ * @events: Events bitmask sent to the driver.
  * @priv_data: client private data
  */
 struct mei_cl_device {
@@ -286,6 +309,13 @@ struct mei_cl_device {
 	uuid_le uuid;
 	struct mei_cl *cl;
 
+	const struct mei_cl_transport_ops *ops;
+
+	struct work_struct event_work;
+	mei_cl_event_cb_t event_cb;
+	void *event_context;
+	unsigned long events;
+
 	void *priv_data;
 };
 
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 92c30a8..054e7e3 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -96,4 +96,15 @@ int __mei_cl_driver_register(struct mei_cl_driver *driver,
 
 void mei_cl_driver_unregister(struct mei_cl_driver *driver);
 
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+
+typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
+			       u32 events, void *context);
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+			  mei_cl_event_cb_t read_cb, void *context);
+
+#define MEI_CL_EVENT_RX 0
+#define MEI_CL_EVENT_TX 1
+
 #endif /* _LINUX_MEI_CL_BUS_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 04/11 V4] mei: bus: Add bus related structures to mei_cl
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (2 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 03/11 V4] mei: bus: Initial implementation for I/O routines Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 05/11 V4] mei: bus: Call bus routines from the core code Tomas Winkler
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

We keep track of all MEI devices on the bus through a specific linked list.
We also have a mei_device instance in the mei_cl structure.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 48 +++++++++++++++++++++++++++++++---------------
 drivers/misc/mei/client.c  |  1 +
 drivers/misc/mei/init.c    |  1 +
 drivers/misc/mei/mei_dev.h |  8 ++++++++
 4 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 43f77b8..5691f83 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -117,38 +117,54 @@ static struct device_type mei_cl_device_type = {
 	.release	= mei_cl_dev_release,
 };
 
-struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
+static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
+						uuid_le uuid)
+{
+	struct mei_cl *cl, *next;
+
+	list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+		if (!uuid_le_cmp(uuid, cl->device_uuid))
+			return cl;
+	}
+
+	return NULL;
+}
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
 				  uuid_le uuid, char *name)
 {
 	struct mei_cl_device *device;
+	struct mei_cl *cl;
 	int status;
 
+	cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
+	if (cl == NULL)
+		return NULL;
+
 	device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
 	if (!device)
 		return NULL;
 
 	device->uuid = uuid;
+	device->cl = cl;
 
-	device->dev.parent = &mei_device->pdev->dev;
+	device->dev.parent = &dev->pdev->dev;
 	device->dev.bus = &mei_cl_bus_type;
 	device->dev.type = &mei_cl_device_type;
 
 	dev_set_name(&device->dev, "%s", name);
 
 	status = device_register(&device->dev);
-	if (status)
-		goto out_err;
+	if (status) {
+		dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
+		kfree(device);
+		return NULL;
+	}
+
+	cl->device = device;
 
 	dev_dbg(&device->dev, "client %s registered\n", name);
 
 	return device;
-
-out_err:
-	dev_err(device->dev.parent, "Failed to register MEI client\n");
-
-	kfree(device);
-
-	return NULL;
 }
 EXPORT_SYMBOL_GPL(mei_cl_add_device);
 
@@ -346,9 +362,10 @@ out:
 
 int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
 {
-	struct mei_cl *cl = NULL;
+	struct mei_cl *cl = device->cl;
 
-	/* TODO: hook between mei_bus_client and mei_cl */
+	if (cl == NULL)
+		return -ENODEV;
 
 	if (device->ops && device->ops->send)
 		return device->ops->send(device, buf, length);
@@ -359,9 +376,10 @@ EXPORT_SYMBOL_GPL(mei_cl_send);
 
 int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
 {
-	struct mei_cl *cl = NULL;
+	struct mei_cl *cl =  device->cl;
 
-	/* TODO: hook between mei_bus_client and mei_cl */
+	if (cl == NULL)
+		return -ENODEV;
 
 	if (device->ops && device->ops->recv)
 		return device->ops->recv(device, buf, length);
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1569afe..e14397b 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -216,6 +216,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
 	init_waitqueue_head(&cl->rx_wait);
 	init_waitqueue_head(&cl->tx_wait);
 	INIT_LIST_HEAD(&cl->link);
+	INIT_LIST_HEAD(&cl->device_link);
 	cl->reading_state = MEI_IDLE;
 	cl->writing_state = MEI_IDLE;
 	cl->dev = dev;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 09a9980..27df330 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -46,6 +46,7 @@ void mei_device_init(struct mei_device *dev)
 {
 	/* setup our list array */
 	INIT_LIST_HEAD(&dev->file_list);
+	INIT_LIST_HEAD(&dev->device_list);
 	mutex_init(&dev->device_lock);
 	init_waitqueue_head(&dev->wait_hw_ready);
 	init_waitqueue_head(&dev->wait_recvd_msg);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 800ac2b..d9da1fb 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -209,6 +209,11 @@ struct mei_cl {
 	enum mei_file_transaction_states writing_state;
 	int sm_state;
 	struct mei_cl_cb *read_cb;
+
+	/* MEI CL bus data */
+	struct mei_cl_device *device;
+	struct list_head device_link;
+	uuid_le device_uuid;
 };
 
 /** struct mei_hw_ops
@@ -424,6 +429,9 @@ struct mei_device {
 
 	struct work_struct init_work;
 
+	/* List of bus devices */
+	struct list_head device_list;
+
 	const struct mei_hw_ops *ops;
 	char hw[0] __aligned(sizeof(void *));
 };
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 05/11 V4] mei: bus: Call bus routines from the core code
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (3 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 04/11 V4] mei: bus: Add bus related structures to mei_cl Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 06/11 V4] mei: bus: Synchronous API for the data transmission Tomas Winkler
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

Register the MEI bus type against the kernel core bus APIs and
call the bus Rx handler from interrupt.c

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c       | 22 ++++++++++++++++++++++
 drivers/misc/mei/interrupt.c |  2 ++
 drivers/misc/mei/mei_dev.h   |  6 +++++-
 drivers/misc/mei/pci-me.c    | 21 +++++++++++++++++++--
 4 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 5691f83..d55f6d8 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -419,3 +419,25 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
+
+void mei_cl_bus_rx_event(struct mei_cl *cl)
+{
+	struct mei_cl_device *device = cl->device;
+
+	if (!device || !device->event_cb)
+		return;
+
+	set_bit(MEI_CL_EVENT_RX, &device->events);
+
+	schedule_work(&device->event_work);
+}
+
+int __init mei_cl_bus_init(struct pci_dev *pdev)
+{
+	return bus_register(&mei_cl_bus_type);
+}
+
+void __exit mei_cl_bus_exit(void)
+{
+	bus_unregister(&mei_cl_bus_type);
+}
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 73fbce3..c478332 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -49,6 +49,8 @@ static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb)
 		cl->reading_state = MEI_READ_COMPLETE;
 		if (waitqueue_active(&cl->rx_wait))
 			wake_up_interruptible(&cl->rx_wait);
+		else
+			mei_cl_bus_rx_event(cl);
 
 	}
 }
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d9da1fb..0391dc9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -292,6 +292,11 @@ struct mei_cl_transport_ops {
 	int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
 };
 
+void mei_cl_bus_rx_event(struct mei_cl *cl);
+int mei_cl_bus_init(struct pci_dev *pdev);
+void mei_cl_bus_exit(void);
+
+
 /**
  * struct mei_cl_device - MEI device handle
  * An mei_cl_device pointer is returned from mei_add_device()
@@ -452,7 +457,6 @@ static inline u32 mei_data2slots(size_t length)
 	return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
 }
 
-
 /*
  * mei init function prototypes
  */
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index b8b5c9c..badc0bd 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -197,7 +197,6 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	mei_pdev = pdev;
 	pci_set_drvdata(pdev, dev);
 
-
 	schedule_delayed_work(&dev->timer_work, HZ);
 
 	mutex_unlock(&mei_mutex);
@@ -351,7 +350,25 @@ static struct pci_driver mei_driver = {
 	.driver.pm = MEI_PM_OPS,
 };
 
-module_pci_driver(mei_driver);
+static int __init mei_init(void)
+{
+	int err;
+
+	err = mei_cl_bus_init(mei_pdev);
+	if (err)
+		return err;
+
+	return pci_register_driver(&mei_driver);
+}
+
+static void __exit mei_exit(void)
+{
+	pci_unregister_driver(&mei_driver);
+	mei_cl_bus_exit();
+}
+
+module_init(mei_init);
+module_exit(mei_exit);
 
 MODULE_AUTHOR("Intel Corporation");
 MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 06/11 V4] mei: bus: Synchronous API for the data transmission
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (4 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 05/11 V4] mei: bus: Call bus routines from the core code Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 07/11 V4] mei: bus: Implement bus driver data setter/getter Tomas Winkler
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

Define a truly synchronous API for the bus Tx path by putting all pending
request to the write list and wait for the interrupt tx handler to wake
us up.
The ___mei_cl_send() out path is also slightly reworked to make it look more
like main.c:mei_write().

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 39 +++++++++++++++++++++++++++++----------
 drivers/misc/mei/mei_dev.h |  1 +
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index d55f6d8..d542950 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -200,7 +200,8 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
 }
 EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
 
-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+			bool blocking)
 {
 	struct mei_device *dev;
 	struct mei_msg_hdr mei_hdr;
@@ -251,11 +252,8 @@ int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
 		cb->buf_idx = 0;
 		mei_hdr.msg_complete = 0;
 		cl->writing_state = MEI_WRITING;
-		list_add_tail(&cb->list, &dev->write_list.list);
-
-		mutex_unlock(&dev->device_lock);
 
-		return length;
+		goto out;
 	}
 
 	dev->hbuf_is_ready = false;
@@ -281,19 +279,30 @@ int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
 	cl->writing_state = MEI_WRITING;
 	cb->buf_idx = mei_hdr.length;
 
-	if (!mei_hdr.msg_complete) {
-		list_add_tail(&cb->list, &dev->write_list.list);
-	} else {
+out:
+	if (mei_hdr.msg_complete) {
 		if (mei_cl_flow_ctrl_reduce(cl)) {
-			err = -EIO;
+			err = -ENODEV;
 			goto out_err;
 		}
-
 		list_add_tail(&cb->list, &dev->write_waiting_list.list);
+	} else {
+		list_add_tail(&cb->list, &dev->write_list.list);
 	}
 
 	mutex_unlock(&dev->device_lock);
 
+	if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
+		if (wait_event_interruptible(cl->tx_wait,
+			cl->writing_state == MEI_WRITE_COMPLETE)) {
+				if (signal_pending(current))
+					err = -EINTR;
+			err = -ERESTARTSYS;
+			mutex_lock(&dev->device_lock);
+			goto out_err;
+		}
+	}
+
 	return mei_hdr.length;
 
 out_err:
@@ -360,6 +369,16 @@ out:
 	return r_length;
 }
 
+inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+	return ___mei_cl_send(cl, buf, length, 0);
+}
+
+inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+	return ___mei_cl_send(cl, buf, length, 1);
+}
+
 int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
 {
 	struct mei_cl *cl = device->cl;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 0391dc9..7199789 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -273,6 +273,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
 				  uuid_le uuid, char *name);
 void mei_cl_remove_device(struct mei_cl_device *device);
 
+int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 07/11 V4] mei: bus: Implement bus driver data setter/getter
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (5 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 06/11 V4] mei: bus: Synchronous API for the data transmission Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 08/11 V4] mei: nfc: Initial nfc implementation Tomas Winkler
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

MEI drivers should be able to carry their private data around.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 12 ++++++++++++
 include/linux/mei_cl_bus.h |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index d542950..bb1cff4 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -439,6 +439,18 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
 }
 EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
 
+void *mei_cl_get_drvdata(const struct mei_cl_device *device)
+{
+	return dev_get_drvdata(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
+
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
+{
+	dev_set_drvdata(&device->dev, data);
+}
+EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
+
 void mei_cl_bus_rx_event(struct mei_cl *cl)
 {
 	struct mei_cl_device *device = cl->device;
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index 054e7e3..e95399e 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -107,4 +107,7 @@ int mei_cl_register_event_cb(struct mei_cl_device *device,
 #define MEI_CL_EVENT_RX 0
 #define MEI_CL_EVENT_TX 1
 
+void *mei_cl_get_drvdata(const struct mei_cl_device *device);
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
+
 #endif /* _LINUX_MEI_CL_BUS_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 08/11 V4] mei: nfc: Initial nfc implementation
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (6 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 07/11 V4] mei: bus: Implement bus driver data setter/getter Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 09/11 V4] mei: nfc: Connect also the regular ME client Tomas Winkler
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

NFC ME device is exported through the MEI bus to be consumed by the
NFC subsystem.

NFC is represented by two mei clients: An info one and the actual
NFC one. In order to properly build the ME id we first need to retrieve
the firmware information from the info client.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/Kconfig   |   7 ++
 drivers/misc/mei/Makefile  |   1 +
 drivers/misc/mei/client.c  |   3 +
 drivers/misc/mei/init.c    |   2 +
 drivers/misc/mei/mei_dev.h |  28 ++++++
 drivers/misc/mei/nfc.c     | 209 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/nfc.h     | 122 ++++++++++++++++++++++++++
 7 files changed, 372 insertions(+)
 create mode 100644 drivers/misc/mei/nfc.c
 create mode 100644 drivers/misc/mei/nfc.h

diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index d21b4d0..66e84ef 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -35,3 +35,10 @@ config INTEL_MEI_ME
 	  82Q33 Express
 	  82X38/X48 Express
 
+config INTEL_MEI_BUS_NFC
+        bool "MEI bus NFC support"
+        depends on INTEL_MEI
+	help
+	  When selecting this option the ME NFC device will be added to the
+	  MEI bus. This is needed by the NFC kernel subsystem for sending and
+	  receiving HCI frames to and from the NFC device.
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 5948621..644f92e 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -11,5 +11,6 @@ mei-objs += main.o
 mei-objs += amthif.o
 mei-objs += wd.o
 mei-objs += bus.o
+mei-$(CONFIG_INTEL_MEI_BUS_NFC) += nfc.o
 mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
 mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e14397b..eb27bf6 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -358,6 +358,9 @@ void mei_host_client_init(struct work_struct *work)
 			mei_amthif_host_init(dev);
 		else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
 			mei_wd_host_init(dev);
+		else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+			mei_nfc_host_init(dev);
+
 	}
 
 	dev->dev_state = MEI_DEV_ENABLED;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 27df330..5de933d 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -206,6 +206,8 @@ void mei_stop(struct mei_device *dev)
 
 	mei_wd_stop(dev);
 
+	mei_nfc_host_exit();
+
 	dev->dev_state = MEI_DEV_POWER_DOWN;
 	mei_reset(dev, 0);
 
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7199789..390d57e 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -499,6 +499,34 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 
 void mei_amthif_run_next_cmd(struct mei_device *dev);
 
+#ifdef CONFIG_INTEL_MEI_BUS_NFC
+/*
+ * NFC functions
+ */
+int mei_nfc_host_init(struct mei_device *dev);
+void mei_nfc_host_exit(void);
+
+/*
+ * NFC Client UUID
+ */
+extern const uuid_le mei_nfc_guid;
+
+#else /* CONFIG_INTEL_MEI_BUS_NFC */
+
+static inline int mei_nfc_host_init(struct mei_device *dev)
+{
+	return 0;
+}
+
+static inline void mei_nfc_host_exit(void)
+{
+	return;
+}
+
+static const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+					    0x94, 0xd4, 0x50, 0x26,
+					    0x67, 0x23, 0x77, 0x5c);
+#endif /* CONFIG_INTEL_MEI_BUS_NFC */
 
 int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
 			struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
new file mode 100644
index 0000000..867cbe7
--- /dev/null
+++ b/drivers/misc/mei/nfc.c
@@ -0,0 +1,209 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/mei.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "client.h"
+#include "nfc.h"
+
+/** mei_nfc_dev - NFC mei device
+ *
+ * @cl_info: NFC info host client
+ * @init_work: perform connection to the info client
+ * @fw_ivn: NFC Intervace Version Number
+ * @vendor_id: NFC manufacturer ID
+ * @radio_type: NFC radio type
+ */
+struct mei_nfc_dev {
+	struct mei_cl *cl_info;
+	struct work_struct init_work;
+	u8 fw_ivn;
+	u8 vendor_id;
+	u8 radio_type;
+};
+
+static struct mei_nfc_dev nfc_dev;
+
+/* UUIDs for NFC F/W clients */
+const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+				     0x94, 0xd4, 0x50, 0x26,
+				     0x67, 0x23, 0x77, 0x5c);
+
+static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
+					0x48, 0xa4, 0xef, 0xab,
+					0xba, 0x8a, 0x12, 0x06);
+
+static void mei_nfc_free(struct mei_nfc_dev *ndev)
+{
+	if (ndev->cl_info) {
+		list_del(&ndev->cl_info->device_link);
+		mei_cl_unlink(ndev->cl_info);
+		kfree(ndev->cl_info);
+	}
+}
+
+static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
+{
+	struct mei_device *dev;
+	struct mei_cl *cl;
+
+	struct mei_nfc_cmd cmd;
+	struct mei_nfc_reply *reply = NULL;
+	struct mei_nfc_if_version *version;
+	size_t if_version_length;
+	int bytes_recv, ret;
+
+	cl = ndev->cl_info;
+	dev = cl->dev;
+
+	memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
+	cmd.command = MEI_NFC_CMD_MAINTENANCE;
+	cmd.data_size = 1;
+	cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
+
+	ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
+		return ret;
+	}
+
+	/* to be sure on the stack we alloc memory */
+	if_version_length = sizeof(struct mei_nfc_reply) +
+		sizeof(struct mei_nfc_if_version);
+
+	reply = kzalloc(if_version_length, GFP_KERNEL);
+	if (!reply)
+		return -ENOMEM;
+
+	bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
+	if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+		dev_err(&dev->pdev->dev, "Could not read IF version\n");
+		ret = -EIO;
+		goto err;
+	}
+
+	version = (struct mei_nfc_if_version *)reply->data;
+
+	ndev->fw_ivn = version->fw_ivn;
+	ndev->vendor_id = version->vendor_id;
+	ndev->radio_type = version->radio_type;
+
+err:
+	kfree(reply);
+	return ret;
+}
+
+static void mei_nfc_init(struct work_struct *work)
+{
+	struct mei_device *dev;
+	struct mei_nfc_dev *ndev;
+	struct mei_cl *cl_info;
+	int ret;
+
+	ndev = container_of(work, struct mei_nfc_dev, init_work);
+
+	cl_info = ndev->cl_info;
+	dev = cl_info->dev;
+
+	mutex_lock(&dev->device_lock);
+
+	if (mei_cl_connect(cl_info, NULL) < 0) {
+		mutex_unlock(&dev->device_lock);
+		dev_err(&dev->pdev->dev,
+			"Could not connect to the NFC INFO ME client");
+
+		goto err;
+	}
+
+	mutex_unlock(&dev->device_lock);
+
+	ret = mei_nfc_if_version(ndev);
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev, "Could not get the NFC interfave version");
+
+		goto err;
+	}
+
+	dev_info(&dev->pdev->dev,
+		"NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
+		ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
+
+	return;
+
+err:
+	mei_nfc_free(ndev);
+
+	return;
+}
+
+
+int mei_nfc_host_init(struct mei_device *dev)
+{
+	struct mei_nfc_dev *ndev = &nfc_dev;
+	struct mei_cl *cl_info;
+	int i, ret;
+
+	/* already initialzed */
+	if (ndev->cl_info)
+		return 0;
+
+	cl_info = mei_cl_allocate(dev);
+	if (!cl_info)
+		return -ENOMEM;
+
+	/* check for valid client id */
+	i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
+	if (i < 0) {
+		dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+		return -ENOENT;
+	}
+
+	cl_info->me_client_id = dev->me_clients[i].client_id;
+
+	ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
+	if (ret)
+		goto err;
+
+	cl_info->device_uuid = mei_nfc_info_guid;
+
+	list_add_tail(&cl_info->device_link, &dev->device_list);
+
+	ndev->cl_info = cl_info;
+
+	INIT_WORK(&ndev->init_work, mei_nfc_init);
+	schedule_work(&ndev->init_work);
+
+	return 0;
+
+err:
+	mei_nfc_free(ndev);
+
+	return ret;
+}
+
+void mei_nfc_host_exit(void)
+{
+	struct mei_nfc_dev *ndev = &nfc_dev;
+
+	mei_nfc_free(ndev);
+}
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
new file mode 100644
index 0000000..59e6703
--- /dev/null
+++ b/drivers/misc/mei/nfc.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Intel MEI Interface Header
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *	Intel Corporation.
+ *	linux-mei@linux.intel.com
+ *	http://www.intel.com
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef _MEI_NFC_H
+#define _MEI_NFC_H
+
+#include <linux/types.h>
+
+struct mei_nfc_cmd {
+	uint8_t command;
+	uint8_t status;
+	uint16_t req_id;
+	uint32_t reserved;
+	uint16_t data_size;
+	uint8_t sub_command;
+	uint8_t data[];
+} __packed;
+
+struct mei_nfc_reply {
+	uint8_t command;
+	uint8_t status;
+	uint16_t req_id;
+	uint32_t reserved;
+	uint16_t data_size;
+	uint8_t sub_command;
+	uint8_t reply_status;
+	uint8_t data[];
+} __packed;
+
+struct mei_nfc_if_version {
+	uint8_t radio_version_sw[3];
+	uint8_t reserved[3];
+	uint8_t radio_version_hw[3];
+	uint8_t i2c_addr;
+	uint8_t fw_ivn;
+	uint8_t vendor_id;
+	uint8_t radio_type;
+} __packed;
+
+struct mei_nfc_connect {
+	uint8_t fw_ivn;
+	uint8_t vendor_id;
+} __packed;
+
+struct mei_nfc_connect_resp {
+	uint8_t fw_ivn;
+	uint8_t vendor_id;
+	uint16_t me_major;
+	uint16_t me_minor;
+	uint16_t me_hotfix;
+	uint16_t me_build;
+} __packed;
+
+#define MEI_NFC_CMD_MAINTENANCE 0x00
+
+#define MEI_NFC_SUBCMD_CONNECT    0x00
+#define MEI_NFC_SUBCMD_IF_VERSION 0x01
+
+#endif /* _MEI_NFC_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 09/11 V4] mei: nfc: Connect also the regular ME client
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (7 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 08/11 V4] mei: nfc: Initial nfc implementation Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 10/11 V4] mei: nfc: Add NFC device to the MEI bus Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 11/11 V4] mei: nfc: Implement MEI bus IO ops Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

After receiving the NFC interface version, IVN and radio type,
we can connect to the the actual nfc ME client and send the
initialization (nfc connect) message.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/nfc.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 867cbe7..b903d82 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -28,6 +28,7 @@
 
 /** mei_nfc_dev - NFC mei device
  *
+ * @cl: NFC host client
  * @cl_info: NFC info host client
  * @init_work: perform connection to the info client
  * @fw_ivn: NFC Intervace Version Number
@@ -35,6 +36,7 @@
  * @radio_type: NFC radio type
  */
 struct mei_nfc_dev {
+	struct mei_cl *cl;
 	struct mei_cl *cl_info;
 	struct work_struct init_work;
 	u8 fw_ivn;
@@ -55,6 +57,12 @@ static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
 
 static void mei_nfc_free(struct mei_nfc_dev *ndev)
 {
+	if (ndev->cl) {
+		list_del(&ndev->cl->device_link);
+		mei_cl_unlink(ndev->cl);
+		kfree(ndev->cl);
+	}
+
 	if (ndev->cl_info) {
 		list_del(&ndev->cl_info->device_link);
 		mei_cl_unlink(ndev->cl_info);
@@ -62,6 +70,73 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
 	}
 }
 
+static int mei_nfc_connect(struct mei_nfc_dev *ndev)
+{
+	struct mei_device *dev;
+	struct mei_cl *cl;
+	struct mei_nfc_cmd *cmd, *reply;
+	struct mei_nfc_connect *connect;
+	struct mei_nfc_connect_resp *connect_resp;
+	size_t connect_length, connect_resp_length;
+	int bytes_recv, ret;
+
+	cl = ndev->cl;
+	dev = cl->dev;
+
+	connect_length = sizeof(struct mei_nfc_cmd) +
+			sizeof(struct mei_nfc_connect);
+
+	connect_resp_length = sizeof(struct mei_nfc_cmd) +
+			sizeof(struct mei_nfc_connect_resp);
+
+	cmd = kzalloc(connect_length, GFP_KERNEL);
+	if (!cmd)
+		return -ENOMEM;
+	connect = (struct mei_nfc_connect *)cmd->data;
+
+	reply = kzalloc(connect_resp_length, GFP_KERNEL);
+	if (!reply) {
+		kfree(cmd);
+		return -ENOMEM;
+	}
+
+	connect_resp = (struct mei_nfc_connect_resp *)reply->data;
+
+	cmd->command = MEI_NFC_CMD_MAINTENANCE;
+	cmd->data_size = 3;
+	cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
+	connect->fw_ivn = ndev->fw_ivn;
+	connect->vendor_id = ndev->vendor_id;
+
+	ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
+		goto err;
+	}
+
+	bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
+	if (bytes_recv < 0) {
+		dev_err(&dev->pdev->dev, "Could not read connect response\n");
+		ret = bytes_recv;
+		goto err;
+	}
+
+	dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
+		connect_resp->fw_ivn, connect_resp->vendor_id);
+
+	dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
+		connect_resp->me_major, connect_resp->me_minor,
+		connect_resp->me_hotfix, connect_resp->me_build);
+
+	ret = 0;
+
+err:
+	kfree(reply);
+	kfree(cmd);
+
+	return ret;
+}
+
 static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
 {
 	struct mei_device *dev;
@@ -117,12 +192,13 @@ static void mei_nfc_init(struct work_struct *work)
 {
 	struct mei_device *dev;
 	struct mei_nfc_dev *ndev;
-	struct mei_cl *cl_info;
+	struct mei_cl *cl_info, *cl;
 	int ret;
 
 	ndev = container_of(work, struct mei_nfc_dev, init_work);
 
 	cl_info = ndev->cl_info;
+	cl = ndev->cl;
 	dev = cl_info->dev;
 
 	mutex_lock(&dev->device_lock);
@@ -148,6 +224,24 @@ static void mei_nfc_init(struct work_struct *work)
 		"NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
 		ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
 
+	mutex_lock(&dev->device_lock);
+
+	if (mei_cl_connect(cl, NULL) < 0) {
+		mutex_unlock(&dev->device_lock);
+		dev_err(&dev->pdev->dev,
+			"Could not connect to the NFC ME client");
+
+		goto err;
+	}
+
+	mutex_unlock(&dev->device_lock);
+
+	ret = mei_nfc_connect(ndev);
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev, "Could not connect to NFC");
+		return;
+	}
+
 	return;
 
 err:
@@ -160,7 +254,7 @@ err:
 int mei_nfc_host_init(struct mei_device *dev)
 {
 	struct mei_nfc_dev *ndev = &nfc_dev;
-	struct mei_cl *cl_info;
+	struct mei_cl *cl_info, *cl  = NULL;
 	int i, ret;
 
 	/* already initialzed */
@@ -168,14 +262,19 @@ int mei_nfc_host_init(struct mei_device *dev)
 		return 0;
 
 	cl_info = mei_cl_allocate(dev);
-	if (!cl_info)
-		return -ENOMEM;
+	cl = mei_cl_allocate(dev);
+
+	if (!cl || !cl_info) {
+		ret = -ENOMEM;
+		goto err;
+	}
 
 	/* check for valid client id */
 	i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
 	if (i < 0) {
 		dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
-		return -ENOENT;
+		ret = -ENOENT;
+		goto err;
 	}
 
 	cl_info->me_client_id = dev->me_clients[i].client_id;
@@ -188,7 +287,26 @@ int mei_nfc_host_init(struct mei_device *dev)
 
 	list_add_tail(&cl_info->device_link, &dev->device_list);
 
+	/* check for valid client id */
+	i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
+	if (i < 0) {
+		dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	cl->me_client_id = dev->me_clients[i].client_id;
+
+	ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
+	if (ret)
+		goto err;
+
+	cl->device_uuid = mei_nfc_guid;
+
+	list_add_tail(&cl->device_link, &dev->device_list);
+
 	ndev->cl_info = cl_info;
+	ndev->cl = cl;
 
 	INIT_WORK(&ndev->init_work, mei_nfc_init);
 	schedule_work(&ndev->init_work);
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 10/11 V4] mei: nfc: Add NFC device to the MEI bus
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (8 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 09/11 V4] mei: nfc: Connect also the regular ME client Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  2013-03-20 22:44 ` [char-misc-next 11/11 V4] mei: nfc: Implement MEI bus IO ops Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

After building its bus name as a string based on its vendor id and radio
type, we can add it to the bus.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/nfc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/nfc.h |  6 ++++++
 2 files changed, 61 insertions(+)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index b903d82..372d336 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -42,6 +42,8 @@ struct mei_nfc_dev {
 	u8 fw_ivn;
 	u8 vendor_id;
 	u8 radio_type;
+
+	char *bus_name;
 };
 
 static struct mei_nfc_dev nfc_dev;
@@ -70,6 +72,39 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
 	}
 }
 
+static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
+{
+	struct mei_device *dev;
+
+	if (!ndev->cl)
+		return -ENODEV;
+
+	dev = ndev->cl->dev;
+
+	switch (ndev->vendor_id) {
+	case MEI_NFC_VENDOR_INSIDE:
+		switch (ndev->radio_type) {
+		case MEI_NFC_VENDOR_INSIDE_UREAD:
+			ndev->bus_name = "microread";
+			return 0;
+
+		default:
+			dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+				ndev->radio_type);
+
+			return -EINVAL;
+		}
+
+	default:
+		dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n",
+			ndev->vendor_id);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int mei_nfc_connect(struct mei_nfc_dev *ndev)
 {
 	struct mei_device *dev;
@@ -191,6 +226,7 @@ err:
 static void mei_nfc_init(struct work_struct *work)
 {
 	struct mei_device *dev;
+	struct mei_cl_device *cldev;
 	struct mei_nfc_dev *ndev;
 	struct mei_cl *cl_info, *cl;
 	int ret;
@@ -242,6 +278,22 @@ static void mei_nfc_init(struct work_struct *work)
 		return;
 	}
 
+	if (mei_nfc_build_bus_name(ndev) < 0) {
+		dev_err(&dev->pdev->dev,
+			"Could not build the bus ID name\n");
+		return;
+	}
+
+	cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name);
+	if (!cldev) {
+		dev_err(&dev->pdev->dev,
+			"Could not add the NFC device to the MEI bus\n");
+
+		goto err;
+	}
+
+	cldev->priv_data = ndev;
+
 	return;
 
 err:
@@ -323,5 +375,8 @@ void mei_nfc_host_exit(void)
 {
 	struct mei_nfc_dev *ndev = &nfc_dev;
 
+	if (ndev->cl && ndev->cl->device)
+		mei_cl_remove_device(ndev->cl->device);
+
 	mei_nfc_free(ndev);
 }
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
index 59e6703..4440436 100644
--- a/drivers/misc/mei/nfc.h
+++ b/drivers/misc/mei/nfc.h
@@ -119,4 +119,10 @@ struct mei_nfc_connect_resp {
 #define MEI_NFC_SUBCMD_CONNECT    0x00
 #define MEI_NFC_SUBCMD_IF_VERSION 0x01
 
+/* Vendors */
+#define MEI_NFC_VENDOR_INSIDE 0x00
+
+/* Radio types */
+#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
+
 #endif /* _MEI_NFC_H */
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 11/11 V4] mei: nfc: Implement MEI bus IO ops
  2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
                   ` (9 preceding siblings ...)
  2013-03-20 22:44 ` [char-misc-next 10/11 V4] mei: nfc: Add NFC device to the MEI bus Tomas Winkler
@ 2013-03-20 22:44 ` Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2013-03-20 22:44 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Samuel Ortiz, Tomas Winkler

From: Samuel Ortiz <sameo@linux.intel.com>

The send ops for NFC builds the command header, updates the request id
and then waits for an ACK.
The recv ops check if it receives data or an ACK and in the latter case
wakes the send ops up.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/nfc.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/mei/nfc.h | 13 +++++++++
 2 files changed, 89 insertions(+)

diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 372d336..14d6076 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -15,6 +15,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
@@ -39,11 +40,15 @@ struct mei_nfc_dev {
 	struct mei_cl *cl;
 	struct mei_cl *cl_info;
 	struct work_struct init_work;
+	wait_queue_head_t send_wq;
 	u8 fw_ivn;
 	u8 vendor_id;
 	u8 radio_type;
 
 	char *bus_name;
+
+	u16 req_id;
+	u16 recv_req_id;
 };
 
 static struct mei_nfc_dev nfc_dev;
@@ -223,6 +228,74 @@ err:
 	return ret;
 }
 
+static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+	struct mei_device *dev;
+	struct mei_nfc_dev *ndev;
+	struct mei_nfc_hci_hdr *hdr;
+	u8 *mei_buf;
+	int err;
+
+	ndev = (struct mei_nfc_dev *) cldev->priv_data;
+	dev = ndev->cl->dev;
+
+	mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
+	if (!mei_buf)
+		return -ENOMEM;
+
+	hdr = (struct mei_nfc_hci_hdr *) mei_buf;
+	hdr->cmd = MEI_NFC_CMD_HCI_SEND;
+	hdr->status = 0;
+	hdr->req_id = ndev->req_id;
+	hdr->reserved = 0;
+	hdr->data_size = length;
+
+	memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
+
+	err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
+
+	kfree(mei_buf);
+
+	if (!wait_event_interruptible_timeout(ndev->send_wq,
+				ndev->recv_req_id == ndev->req_id, HZ)) {
+		dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
+		err = -ETIMEDOUT;
+	} else {
+		ndev->req_id++;
+	}
+
+	return err;
+}
+
+static int mei_nfc_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+	struct mei_nfc_dev *ndev;
+	struct mei_nfc_hci_hdr *hci_hdr;
+	int received_length;
+
+	ndev = (struct mei_nfc_dev *)cldev->priv_data;
+
+	received_length = __mei_cl_recv(ndev->cl, buf, length);
+	if (received_length < 0)
+		return received_length;
+
+	hci_hdr = (struct mei_nfc_hci_hdr *) buf;
+
+	if (hci_hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
+		ndev->recv_req_id = hci_hdr->req_id;
+		wake_up(&ndev->send_wq);
+
+		return 0;
+	}
+
+	return received_length;
+}
+
+static struct mei_cl_transport_ops nfc_ops = {
+	.send = mei_nfc_send,
+	.recv = mei_nfc_recv,
+};
+
 static void mei_nfc_init(struct work_struct *work)
 {
 	struct mei_device *dev;
@@ -293,6 +366,7 @@ static void mei_nfc_init(struct work_struct *work)
 	}
 
 	cldev->priv_data = ndev;
+	cldev->ops = &nfc_ops;
 
 	return;
 
@@ -359,8 +433,10 @@ int mei_nfc_host_init(struct mei_device *dev)
 
 	ndev->cl_info = cl_info;
 	ndev->cl = cl;
+	ndev->req_id = 1;
 
 	INIT_WORK(&ndev->init_work, mei_nfc_init);
+	init_waitqueue_head(&ndev->send_wq);
 	schedule_work(&ndev->init_work);
 
 	return 0;
diff --git a/drivers/misc/mei/nfc.h b/drivers/misc/mei/nfc.h
index 4440436..12e48d3 100644
--- a/drivers/misc/mei/nfc.h
+++ b/drivers/misc/mei/nfc.h
@@ -114,11 +114,24 @@ struct mei_nfc_connect_resp {
 	uint16_t me_build;
 } __packed;
 
+struct mei_nfc_hci_hdr {
+	u8 cmd;
+	u8 status;
+	u16 req_id;
+	u32 reserved;
+	u16 data_size;
+} __packed;
+
 #define MEI_NFC_CMD_MAINTENANCE 0x00
+#define MEI_NFC_CMD_HCI_SEND 0x01
+#define MEI_NFC_CMD_HCI_RECV 0x02
 
 #define MEI_NFC_SUBCMD_CONNECT    0x00
 #define MEI_NFC_SUBCMD_IF_VERSION 0x01
 
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+
 /* Vendors */
 #define MEI_NFC_VENDOR_INSIDE 0x00
 
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation
  2013-03-20 22:44 ` [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation Tomas Winkler
@ 2013-03-25 20:28   ` Greg KH
  2013-03-26 13:33     ` Samuel Ortiz
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2013-03-25 20:28 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: arnd, linux-kernel, Samuel Ortiz

On Thu, Mar 21, 2013 at 12:44:19AM +0200, Tomas Winkler wrote:
> From: Samuel Ortiz <sameo@linux.intel.com>
> 
> mei cleint bus will present some of the me clients

s/me /mei /

> as devices for other standard subsystems
> 
> Implement the probe, remove, match and the device addtion routines.
> A mei-cleint-bus.txt document describing the rationale and the API usage
> is also added.
> 
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
> ---
>  Documentation/misc-devices/mei/mei-client-bus.txt | 143 ++++++++++++++++++++
>  drivers/misc/mei/Makefile                         |   1 +
>  drivers/misc/mei/bus.c                            | 151 ++++++++++++++++++++++
>  drivers/misc/mei/mei_dev.h                        |  27 ++++
>  include/linux/mei_cl_bus.h                        |  92 +++++++++++++
>  5 files changed, 414 insertions(+)
>  create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt

Shouldn't you also create Documentation/ABI/ entries as well?

> +#define NFC_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
> +			       0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
> +
> +static struct mei_cl_id contact_mei_cl_tbl[] = {
> +	{ CONTACT_DRIVER_NAME, NFC_UUID },
> +
> +	/* required last entry */
> +	{ }
> +};

What about MODULE_DEVICE() functionality for this structure?  Don't you
need/want that as well?


> +/**
> + * struct mei_cl_device - MEI device handle
> + * An mei_cl_device pointer is returned from mei_add_device()
> + * and links MEI bus clients to their actual ME host client pointer.
> + * Drivers for MEI devices will get an mei_cl_device pointer
> + * when being probed and shall use it for doing ME bus I/O.
> + *
> + * @dev: linux driver model device pointer
> + * @uuid: me client uuid
> + * @cl: mei client
> + * @priv_data: client private data
> + */
> +struct mei_cl_device {
> +	struct device dev;
> +
> +	uuid_le uuid;
> +	struct mei_cl *cl;
> +
> +	void *priv_data;
> +};

Why is priv_data needed?  What's wrong with the pointer provided to you
in struct device?

> +++ b/include/linux/mei_cl_bus.h
> @@ -0,0 +1,92 @@
> +/******************************************************************************
> + * Intel Management Engine Interface (Intel MEI) Linux driver
> + * Intel MEI Interface Header
> + *
> + * This file is provided under a dual BSD/GPLv2 license.  When using or
> + * redistributing this file, you may do so under either license.
> + *
> + * GPL LICENSE SUMMARY
> + *
> + * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
> + * USA

Are you really going to track the movements of the FSF for the next 40+
years?

> + * The full GNU General Public License is included in this distribution
> + * in the file called LICENSE.GPL.

Not needed for an in-kernel header file, right?

> + *
> + * Contact Information:
> + *	Intel Corporation.
> + *	linux-mei@linux.intel.com
> + *	http://www.intel.com
> + *
> + * BSD LICENSE

Wait, you are putting code that has EXPORT_SYMBOL_GPL() usage under a
GPL/BSD license?  I need an Intel lawyer signed-off-by: on the patch
before I can accept that.

> +struct mei_cl_driver {
> +	struct device_driver driver;
> +	const char *name;

What's wrong with the driver.name field?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation
  2013-03-25 20:28   ` Greg KH
@ 2013-03-26 13:33     ` Samuel Ortiz
  2013-03-26 22:01       ` Samuel Ortiz
  2013-03-26 23:21       ` Greg KH
  0 siblings, 2 replies; 16+ messages in thread
From: Samuel Ortiz @ 2013-03-26 13:33 UTC (permalink / raw)
  To: Greg KH; +Cc: Tomas Winkler, arnd, linux-kernel

Hi Greg,

On Mon, Mar 25, 2013 at 01:28:55PM -0700, Greg KH wrote:
> On Thu, Mar 21, 2013 at 12:44:19AM +0200, Tomas Winkler wrote:
> >  create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
> 
> Shouldn't you also create Documentation/ABI/ entries as well?
You mean for the bus specific stuff or for the /dev/mei entry ?
For the bus parts, we're not adding any MEI specific sysfs entries. What
should we document ?

 
> > +#define NFC_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
> > +			       0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
> > +
> > +static struct mei_cl_id contact_mei_cl_tbl[] = {
> > +	{ CONTACT_DRIVER_NAME, NFC_UUID },
> > +
> > +	/* required last entry */
> > +	{ }
> > +};
> 
> What about MODULE_DEVICE() functionality for this structure?  Don't you
> need/want that as well?
I was planning to do that as a separate mod_devicetable.h patch once this
code gets merged, but I guess it makes sense to include it with this patchset.
It reminds me that I should remove the uuid_le field from the mei_cl_id
structure, it's useless.


> > +/**
> > + * struct mei_cl_device - MEI device handle
> > + * An mei_cl_device pointer is returned from mei_add_device()
> > + * and links MEI bus clients to their actual ME host client pointer.
> > + * Drivers for MEI devices will get an mei_cl_device pointer
> > + * when being probed and shall use it for doing ME bus I/O.
> > + *
> > + * @dev: linux driver model device pointer
> > + * @uuid: me client uuid
> > + * @cl: mei client
> > + * @priv_data: client private data
> > + */
> > +struct mei_cl_device {
> > +	struct device dev;
> > +
> > +	uuid_le uuid;
> > +	struct mei_cl *cl;
> > +
> > +	void *priv_data;
> > +};
> 
> Why is priv_data needed?  What's wrong with the pointer provided to you
> in struct device?
mei_cl_device->dev->p->driver_data is used by mei drivers to carry their
private data around, we define mei_cl_get_clientdata/mei_cl_set_clientdata for
that and keep the mei_cl_device structure opaque to them.
mei_cl_device->priv_data is used internally by the drivers/misc/mei/ bus
related code to carry technology specific pointers. drivers/misc/mei/nfc.c
uses it to fetch its private data when it gets a mei_cl_device pointer.



> > + *
> > + * Contact Information:
> > + *	Intel Corporation.
> > + *	linux-mei@linux.intel.com
> > + *	http://www.intel.com
> > + *
> > + * BSD LICENSE
> 
> Wait, you are putting code that has EXPORT_SYMBOL_GPL() usage under a
> GPL/BSD license?  I need an Intel lawyer signed-off-by: on the patch
> before I can accept that.
Sorry about that. We changed our EXPORT_SYMBOL to EXPORT_SYMBOL_GPL when you
asked for it, and I missed changing this header file at the same time. I will
actually remove the licensing terms from this file.


> > +struct mei_cl_driver {
> > +	struct device_driver driver;
> > +	const char *name;
> 
> What's wrong with the driver.name field?
>From your initial comments on patchset v1:

"
	> +static struct mei_bus_driver contact_driver = {
	> +     .driver = {
	> +                .name = CONTAC_DRIVER_NAME,
	> +               },

	Can't you put a name field in your mei_bus_driver structure and then
	copy it to the version in the driver model?  That's what other bus
	drivers do and it makes more sense.
"

And you were right, that is indeed what other bus drivers do. Did I
misunderstand you here ?

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation
  2013-03-26 13:33     ` Samuel Ortiz
@ 2013-03-26 22:01       ` Samuel Ortiz
  2013-03-26 23:21       ` Greg KH
  1 sibling, 0 replies; 16+ messages in thread
From: Samuel Ortiz @ 2013-03-26 22:01 UTC (permalink / raw)
  To: Greg KH; +Cc: Tomas Winkler, arnd, linux-kernel

On Tue, Mar 26, 2013 at 02:33:26PM +0100, Samuel Ortiz wrote:
> On Mon, Mar 25, 2013 at 01:28:55PM -0700, Greg KH wrote:
> > On Thu, Mar 21, 2013 at 12:44:19AM +0200, Tomas Winkler wrote:
> > >  create mode 100644 Documentation/misc-devices/mei/mei-client-bus.txt
> > 
> > Shouldn't you also create Documentation/ABI/ entries as well?
> You mean for the bus specific stuff or for the /dev/mei entry ?
> For the bus parts, we're not adding any MEI specific sysfs entries. What
> should we document ?
I'm adding a modalias sysfs attribute, so I'll have to add an ABI
documentation entry for that.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation
  2013-03-26 13:33     ` Samuel Ortiz
  2013-03-26 22:01       ` Samuel Ortiz
@ 2013-03-26 23:21       ` Greg KH
  1 sibling, 0 replies; 16+ messages in thread
From: Greg KH @ 2013-03-26 23:21 UTC (permalink / raw)
  To: Samuel Ortiz; +Cc: Tomas Winkler, arnd, linux-kernel

On Tue, Mar 26, 2013 at 02:33:26PM +0100, Samuel Ortiz wrote:
> > > +/**
> > > + * struct mei_cl_device - MEI device handle
> > > + * An mei_cl_device pointer is returned from mei_add_device()
> > > + * and links MEI bus clients to their actual ME host client pointer.
> > > + * Drivers for MEI devices will get an mei_cl_device pointer
> > > + * when being probed and shall use it for doing ME bus I/O.
> > > + *
> > > + * @dev: linux driver model device pointer
> > > + * @uuid: me client uuid
> > > + * @cl: mei client
> > > + * @priv_data: client private data
> > > + */
> > > +struct mei_cl_device {
> > > +	struct device dev;
> > > +
> > > +	uuid_le uuid;
> > > +	struct mei_cl *cl;
> > > +
> > > +	void *priv_data;
> > > +};
> > 
> > Why is priv_data needed?  What's wrong with the pointer provided to you
> > in struct device?
> mei_cl_device->dev->p->driver_data is used by mei drivers to carry their
> private data around, we define mei_cl_get_clientdata/mei_cl_set_clientdata for
> that and keep the mei_cl_device structure opaque to them.
> mei_cl_device->priv_data is used internally by the drivers/misc/mei/ bus
> related code to carry technology specific pointers. drivers/misc/mei/nfc.c
> uses it to fetch its private data when it gets a mei_cl_device pointer.

Ugh, that looks like a mess, but ok, if you say it is needed, I'll trust
you.

> > > +struct mei_cl_driver {
> > > +	struct device_driver driver;
> > > +	const char *name;
> > 
> > What's wrong with the driver.name field?
> >From your initial comments on patchset v1:
> 
> "
> 	> +static struct mei_bus_driver contact_driver = {
> 	> +     .driver = {
> 	> +                .name = CONTAC_DRIVER_NAME,
> 	> +               },
> 
> 	Can't you put a name field in your mei_bus_driver structure and then
> 	copy it to the version in the driver model?  That's what other bus
> 	drivers do and it makes more sense.
> "
> 
> And you were right, that is indeed what other bus drivers do. Did I
> misunderstand you here ?

No, you are right, sorry for giving conflicting information, it's fine
as-is.

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-03-26 23:21 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-20 22:44 [char-misc-next 00/11 V4] Add Client MEI bus and NFC device Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 01/11 V4] mei: bus: Initial MEI Client bus type implementation Tomas Winkler
2013-03-25 20:28   ` Greg KH
2013-03-26 13:33     ` Samuel Ortiz
2013-03-26 22:01       ` Samuel Ortiz
2013-03-26 23:21       ` Greg KH
2013-03-20 22:44 ` [char-misc-next 02/11 V4] mei: bus: Implement driver registration Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 03/11 V4] mei: bus: Initial implementation for I/O routines Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 04/11 V4] mei: bus: Add bus related structures to mei_cl Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 05/11 V4] mei: bus: Call bus routines from the core code Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 06/11 V4] mei: bus: Synchronous API for the data transmission Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 07/11 V4] mei: bus: Implement bus driver data setter/getter Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 08/11 V4] mei: nfc: Initial nfc implementation Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 09/11 V4] mei: nfc: Connect also the regular ME client Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 10/11 V4] mei: nfc: Add NFC device to the MEI bus Tomas Winkler
2013-03-20 22:44 ` [char-misc-next 11/11 V4] mei: nfc: Implement MEI bus IO ops Tomas Winkler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.