Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7bc6faac authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

greybus: create host-device compilation unit



Move everything host-device related to hd.c and hd.h.

Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Reviewed-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 04fdd6a5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
greybus-y :=	core.o		\
		debugfs.o	\
		hd.o		\
		manifest.o	\
		endo.o		\
		module.o	\
+0 −100
Original line number Diff line number Diff line
@@ -146,106 +146,6 @@ void greybus_deregister_driver(struct greybus_driver *driver)
}
EXPORT_SYMBOL_GPL(greybus_deregister_driver);


static DEFINE_MUTEX(hd_mutex);

static void free_hd(struct kref *kref)
{
	struct greybus_host_device *hd;

	hd = container_of(kref, struct greybus_host_device, kref);

	ida_destroy(&hd->cport_id_map);
	kfree(hd);
	mutex_unlock(&hd_mutex);
}

struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
					      struct device *parent,
					      size_t buffer_size_max,
					      size_t num_cports)
{
	struct greybus_host_device *hd;

	/*
	 * Validate that the driver implements all of the callbacks
	 * so that we don't have to every time we make them.
	 */
	if ((!driver->message_send) || (!driver->message_cancel)) {
		pr_err("Must implement all greybus_host_driver callbacks!\n");
		return ERR_PTR(-EINVAL);
	}

	if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
		dev_err(parent, "greybus host-device buffers too small\n");
		return ERR_PTR(-EINVAL);
	}

	if (num_cports == 0 || num_cports > CPORT_ID_MAX) {
		dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports);
		return ERR_PTR(-EINVAL);
	}

	/*
	 * Make sure to never allocate messages larger than what the Greybus
	 * protocol supports.
	 */
	if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
		dev_warn(parent, "limiting buffer size to %u\n",
			 GB_OPERATION_MESSAGE_SIZE_MAX);
		buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
	}

	hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
	if (!hd)
		return ERR_PTR(-ENOMEM);

	kref_init(&hd->kref);
	hd->parent = parent;
	hd->driver = driver;
	INIT_LIST_HEAD(&hd->interfaces);
	INIT_LIST_HEAD(&hd->connections);
	ida_init(&hd->cport_id_map);
	hd->buffer_size_max = buffer_size_max;
	hd->num_cports = num_cports;

	/*
	 * Initialize AP's SVC protocol connection:
	 *
	 * This is required as part of early initialization of the host device
	 * as we need this connection in order to start any kind of message
	 * exchange between the AP and the SVC. SVC will start with a
	 * 'get-version' request followed by a 'svc-hello' message and at that
	 * time we will create a fully initialized svc-connection, as we need
	 * endo-id and AP's interface id for that.
	 */
	if (!gb_ap_svc_connection_create(hd)) {
		kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
		return ERR_PTR(-ENOMEM);
	}

	return hd;
}
EXPORT_SYMBOL_GPL(greybus_create_hd);

void greybus_remove_hd(struct greybus_host_device *hd)
{
	/*
	 * Tear down all interfaces, modules, and the endo that is associated
	 * with this host controller before freeing the memory associated with
	 * the host controller.
	 */
	gb_interfaces_remove(hd);
	gb_endo_remove(hd->endo);

	/* Is the SVC still using the partially uninitialized connection ? */
	if (hd->initial_svc_connection)
		gb_connection_destroy(hd->initial_svc_connection);

	kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
}
EXPORT_SYMBOL_GPL(greybus_remove_hd);

static int __init gb_init(void)
{
	int retval;
+1 −47
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "greybus_manifest.h"
#include "greybus_protocols.h"
#include "manifest.h"
#include "hd.h"
#include "endo.h"
#include "svc.h"
#include "firmware.h"
@@ -57,53 +58,6 @@
#define CPORT_ID_MAX	4095		/* UniPro max id is 4095 */
#define CPORT_ID_BAD	U16_MAX

struct greybus_host_device;

/* Greybus "Host driver" structure, needed by a host controller driver to be
 * able to handle both SVC control as well as "real" greybus messages
 */
struct greybus_host_driver {
	size_t	hd_priv_size;

	int (*cport_enable)(struct greybus_host_device *hd, u16 cport_id);
	int (*cport_disable)(struct greybus_host_device *hd, u16 cport_id);
	int (*message_send)(struct greybus_host_device *hd, u16 dest_cport_id,
			struct gb_message *message, gfp_t gfp_mask);
	void (*message_cancel)(struct gb_message *message);
	int (*latency_tag_enable)(struct greybus_host_device *hd, u16 cport_id);
	int (*latency_tag_disable)(struct greybus_host_device *hd,
				   u16 cport_id);
};

struct greybus_host_device {
	struct kref kref;
	struct device *parent;
	const struct greybus_host_driver *driver;

	struct list_head interfaces;
	struct list_head connections;
	struct ida cport_id_map;

	/* Number of CPorts supported by the UniPro IP */
	size_t num_cports;

	/* Host device buffer constraints */
	size_t buffer_size_max;

	struct gb_endo *endo;
	struct gb_connection *initial_svc_connection;
	struct gb_svc *svc;

	/* Private data for the host driver */
	unsigned long hd_priv[0] __aligned(sizeof(s64));
};

struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd,
					      struct device *parent,
					      size_t buffer_size_max,
					      size_t num_cports);
void greybus_remove_hd(struct greybus_host_device *hd);

struct greybus_driver {
	const char *name;

+115 −0
Original line number Diff line number Diff line
/*
 * Greybus Host Device
 *
 * Copyright 2014-2015 Google Inc.
 * Copyright 2014-2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/slab.h>

#include "greybus.h"

static DEFINE_MUTEX(hd_mutex);


static void free_hd(struct kref *kref)
{
	struct greybus_host_device *hd;

	hd = container_of(kref, struct greybus_host_device, kref);

	ida_destroy(&hd->cport_id_map);
	kfree(hd);
	mutex_unlock(&hd_mutex);
}

struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver,
					      struct device *parent,
					      size_t buffer_size_max,
					      size_t num_cports)
{
	struct greybus_host_device *hd;

	/*
	 * Validate that the driver implements all of the callbacks
	 * so that we don't have to every time we make them.
	 */
	if ((!driver->message_send) || (!driver->message_cancel)) {
		pr_err("Must implement all greybus_host_driver callbacks!\n");
		return ERR_PTR(-EINVAL);
	}

	if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) {
		dev_err(parent, "greybus host-device buffers too small\n");
		return ERR_PTR(-EINVAL);
	}

	if (num_cports == 0 || num_cports > CPORT_ID_MAX) {
		dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports);
		return ERR_PTR(-EINVAL);
	}

	/*
	 * Make sure to never allocate messages larger than what the Greybus
	 * protocol supports.
	 */
	if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) {
		dev_warn(parent, "limiting buffer size to %u\n",
			 GB_OPERATION_MESSAGE_SIZE_MAX);
		buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
	}

	hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL);
	if (!hd)
		return ERR_PTR(-ENOMEM);

	kref_init(&hd->kref);
	hd->parent = parent;
	hd->driver = driver;
	INIT_LIST_HEAD(&hd->interfaces);
	INIT_LIST_HEAD(&hd->connections);
	ida_init(&hd->cport_id_map);
	hd->buffer_size_max = buffer_size_max;
	hd->num_cports = num_cports;

	/*
	 * Initialize AP's SVC protocol connection:
	 *
	 * This is required as part of early initialization of the host device
	 * as we need this connection in order to start any kind of message
	 * exchange between the AP and the SVC. SVC will start with a
	 * 'get-version' request followed by a 'svc-hello' message and at that
	 * time we will create a fully initialized svc-connection, as we need
	 * endo-id and AP's interface id for that.
	 */
	if (!gb_ap_svc_connection_create(hd)) {
		kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
		return ERR_PTR(-ENOMEM);
	}

	return hd;
}
EXPORT_SYMBOL_GPL(greybus_create_hd);

void greybus_remove_hd(struct greybus_host_device *hd)
{
	/*
	 * Tear down all interfaces, modules, and the endo that is associated
	 * with this host controller before freeing the memory associated with
	 * the host controller.
	 */
	gb_interfaces_remove(hd);
	gb_endo_remove(hd->endo);

	/* Is the SVC still using the partially uninitialized connection ? */
	if (hd->initial_svc_connection)
		gb_connection_destroy(hd->initial_svc_connection);

	kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
}
EXPORT_SYMBOL_GPL(greybus_remove_hd);
+61 −0
Original line number Diff line number Diff line
/*
 * Greybus Host Device
 *
 * Copyright 2014-2015 Google Inc.
 * Copyright 2014-2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#ifndef __HD_H
#define __HD_H

struct greybus_host_device;
struct gb_message;

/* Greybus "Host driver" structure, needed by a host controller driver to be
 * able to handle both SVC control as well as "real" greybus messages
 */
struct greybus_host_driver {
	size_t	hd_priv_size;

	int (*cport_enable)(struct greybus_host_device *hd, u16 cport_id);
	int (*cport_disable)(struct greybus_host_device *hd, u16 cport_id);
	int (*message_send)(struct greybus_host_device *hd, u16 dest_cport_id,
			struct gb_message *message, gfp_t gfp_mask);
	void (*message_cancel)(struct gb_message *message);
	int (*latency_tag_enable)(struct greybus_host_device *hd, u16 cport_id);
	int (*latency_tag_disable)(struct greybus_host_device *hd,
				   u16 cport_id);
};

struct greybus_host_device {
	struct kref kref;
	struct device *parent;
	const struct greybus_host_driver *driver;

	struct list_head interfaces;
	struct list_head connections;
	struct ida cport_id_map;

	/* Number of CPorts supported by the UniPro IP */
	size_t num_cports;

	/* Host device buffer constraints */
	size_t buffer_size_max;

	struct gb_endo *endo;
	struct gb_connection *initial_svc_connection;
	struct gb_svc *svc;

	/* Private data for the host driver */
	unsigned long hd_priv[0] __aligned(sizeof(s64));
};

struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd,
					      struct device *parent,
					      size_t buffer_size_max,
					      size_t num_cports);
void greybus_remove_hd(struct greybus_host_device *hd);

#endif	/* __HD_H */