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

Commit 0f37860d authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

greybus: kill the endo



Remove the now unused endo and module code.

Note that the never-implemented serial and version attributes of the
endo can be implemented as svc attributes if needed.

Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent dc3da5db
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -2,8 +2,6 @@ greybus-y := core.o \
		debugfs.o	\
		hd.o		\
		manifest.o	\
		endo.o		\
		module.o	\
		interface.o	\
		bundle.o	\
		connection.o	\
+0 −20
Original line number Diff line number Diff line
@@ -78,23 +78,12 @@ static int greybus_module_match(struct device *dev, struct device_driver *drv)
static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct gb_host_device *hd = NULL;
	struct gb_module *module = NULL;
	struct gb_interface *intf = NULL;
	struct gb_bundle *bundle = NULL;
	struct gb_svc *svc = NULL;

	if (is_gb_endo(dev)) {
		/*
		 * Not much to do for an endo, just fall through, as the
		 * "default" attributes are good enough for us.
		 */
		return 0;
	}

	if (is_gb_host_device(dev)) {
		hd = to_gb_host_device(dev);
	} else if (is_gb_module(dev)) {
		module = to_gb_module(dev);
	} else if (is_gb_interface(dev)) {
		intf = to_gb_interface(dev);
	} else if (is_gb_bundle(dev)) {
@@ -214,12 +203,6 @@ static int __init gb_init(void)
		goto error_operation;
	}

	retval = gb_endo_init();
	if (retval) {
		pr_err("gb_endo_init failed (%d)\n", retval);
		goto error_endo;
	}

	retval = gb_control_protocol_init();
	if (retval) {
		pr_err("gb_control_protocol_init failed\n");
@@ -245,8 +228,6 @@ static int __init gb_init(void)
error_svc:
	gb_control_protocol_exit();
error_control:
	gb_endo_exit();
error_endo:
	gb_operation_exit();
error_operation:
	gb_hd_exit();
@@ -264,7 +245,6 @@ static void __exit gb_exit(void)
	gb_firmware_protocol_exit();
	gb_svc_protocol_exit();
	gb_control_protocol_exit();
	gb_endo_exit();
	gb_operation_exit();
	gb_hd_exit();
	bus_unregister(&greybus_bus_type);

drivers/staging/greybus/endo.c

deleted100644 → 0
+0 −520
Original line number Diff line number Diff line
/*
 * Greybus endo code
 *
 * Copyright 2014-2015 Google Inc.
 * Copyright 2014-2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#include "greybus.h"

/* Endo ID (16 bits long) Masks */
#define ENDO_ID_MASK				0xFFFF
#define ENDO_LARGE_MASK				0x1000
#define ENDO_MEDIUM_MASK			0x0400
#define ENDO_MINI_MASK				0x0100

#define ENDO_FRONT_MASK(id)			((id) >> 13)
#define ENDO_BACK_SIDE_RIBS_MASK(ribs)		((1 << (ribs)) - 1)

/*
 * endo_is_medium() should be used only if endo isn't large. And endo_is_mini()
 * should be used only if endo isn't large or medium.
 */
#define endo_is_large(id)			((id) & ENDO_LARGE_MASK)
#define endo_is_medium(id)			((id) & ENDO_MEDIUM_MASK)
#define endo_is_mini(id)			((id) & ENDO_MINI_MASK)

#define endo_back_left_ribs(id, ribs)		(((id) >> (ribs)) & ENDO_BACK_SIDE_RIBS_MASK(ribs))
#define endo_back_right_ribs(id, ribs)		((id) & ENDO_BACK_SIDE_RIBS_MASK(ribs))

/*
 * An Endo has interface block positions on the front and back.
 * Each has numeric ID, starting with 1 (interface 0 represents
 * the SVC within the Endo itself).  The maximum interface ID is the
 * also the number of non-SVC interfaces possible on the endo.
 *
 * Total number of interfaces:
 * - Front: 4
 * - Back left: max_ribs + 1
 * - Back right: max_ribs + 1
 */
#define max_endo_interface_id(endo_layout) \
		(4 + ((endo_layout)->max_ribs + 1) * 2)

static struct ida greybus_endo_id_map;

/* endo sysfs attributes */
static ssize_t serial_number_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct gb_endo *endo = to_gb_endo(dev);

	return sprintf(buf, "%s\n", &endo->svc_info.serial_number[0]);
}
static DEVICE_ATTR_RO(serial_number);

static ssize_t version_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	struct gb_endo *endo = to_gb_endo(dev);

	return sprintf(buf, "%s\n", &endo->svc_info.version[0]);
}
static DEVICE_ATTR_RO(version);

static struct attribute *svc_attrs[] = {
	&dev_attr_serial_number.attr,
	&dev_attr_version.attr,
	NULL,
};

static const struct attribute_group svc_group = {
	.attrs = svc_attrs,
	.name = "svc",
};

static const struct attribute_group *endo_groups[] = {
	&svc_group,
	NULL,
};

static void gb_endo_release(struct device *dev)
{
	struct gb_endo *endo = to_gb_endo(dev);

	ida_simple_remove(&greybus_endo_id_map, endo->dev_id);
	kfree(endo);
}

struct device_type greybus_endo_type = {
	.name =		"greybus_endo",
	.release =	gb_endo_release,
};


/* Validate Endo ID */

/*
 * The maximum module height is 2 units.  This means any adjacent pair of bits
 * in the left or right mask must have at least one bit set.
 */
static inline bool modules_oversized(unsigned int count, unsigned int mask)
{
	int i;

	for (i = 0; i < count - 1; i++)
		if (!(mask & (0x3 << i)))
			return true;

	return false;
}

/* Reverse a number of least significant bits in a value */
static u8 reverse_bits(unsigned int value, unsigned int bits)
{
	u8 result = 0;
	u8 result_mask = 1 << (bits - 1);
	u8 value_mask = 1;

	while (value && result_mask) {
		if (value & value_mask) {
			result |= result_mask;
			value ^= value_mask;
		}
		value_mask <<= 1;
		result_mask >>= 1;
	}

	return result;
}

/*
 * An Endo can have at most one instance of a single rib spanning its whole
 * width.  That is, the left and right bit masks representing the rib positions
 * must have at most one bit set in both masks.
 */
static bool single_cross_rib(u8 left_ribs, u8 right_ribs)
{
	u8 span_ribs = left_ribs & right_ribs;

	/* Power of 2 ? */
	if (span_ribs & (span_ribs - 1))
		return false;
	return true;
}

/*
 * Each Endo size has its own set of front module configurations.  For most, the
 * resulting rib mask is the same regardless of the Endo size.  The mini Endo
 * has a few differences though.
 *
 * Endo front has 4 interface blocks and 3 rib positions. A maximum of 2 ribs
 * are allowed to be present for any endo type.
 *
 * This routine validates front mask and sets 'front_ribs', its 3 least
 * significant bits represent front ribs mask, other are 0.  The front values
 * should be within range (1..6).
 *
 * front_ribs bitmask:
 * - Bit 0: 1st rib location from top, i.e. between interface 1 and 2.
 * - Bit 1: 2nd rib location from top, i.e. between interface 2 and 3.
 * - Bit 2: 3rd rib location from top, i.e. between interface 3 and 4.
 */
static bool validate_front_ribs(struct gb_host_device *hd,
				struct endo_layout *layout, bool mini,
				u16 endo_id)
{
	u8 front_mask = ENDO_FRONT_MASK(endo_id);

	/* Verify front endo mask is in valid range, i.e. 1-6 */

	switch (front_mask) {
	case 1:
		layout->front_ribs = 0x0;
		break;
	case 2:
		layout->front_ribs = 0x1;
		break;
	case 3:
		layout->front_ribs = 0x4;
		break;
	case 4:
		layout->front_ribs = mini ? 0x2 : 0x3;
		break;
	case 5:
		layout->front_ribs = mini ? 0x2 : 0x6;
		break;
	case 6:
		layout->front_ribs = 0x5;
		break;
	default:
		dev_err(&hd->dev,
			"%s: Invalid endo front mask 0x%02x, id 0x%04x\n",
			__func__, front_mask, endo_id);
		return false;
	}

	return true;
}

/*
 * The rear of an endo has a single vertical "spine", and the modules placed on
 * the left and right of that spine are separated by ribs.  Only one "cross"
 * (i.e. rib that spans the entire width) is allowed of the back of the endo;
 * all other ribs reach from the spine to the left or right edge.
 *
 * The width of the module positions on the left and right of the spine are
 * determined by the width of the endo (either 1 or 2 "units").  The height of
 * the modules is determined by the placement of the ribs (a module can be
 * either 1 or 2 units high).
 *
 * The lower 13 bits of the 16-bit endo id are used to encode back ribs
 * information.  The large form factor endo uses all of these bits; the medium
 * and mini form factors leave some bits unused (such bits shall be ignored, and
 * are 0 for the purposes of this endo id definition).
 *
 * Each defined bit represents a rib position on one or the other side
 * of the spine on the back of an endo.  If that bit is set (1), it
 * means a rib is present in the corresponding location; otherwise
 * there is no rib there.
 *
 * Rotating an endo 180 degrees does not produce a new rib configuration. A
 * single endo id represents a specific configuration of ribs without regard to
 * its rotational orientation.  We define one canonical id to represent a
 * particular endo configuration.
 */
static bool validate_back_ribs(struct gb_host_device *hd,
			       struct endo_layout *layout, u16 endo_id)
{
	u8 max_ribs = layout->max_ribs;
	u8 left_ribs;
	u8 right_ribs;

	/* Extract the left and right rib masks */
	left_ribs = endo_back_left_ribs(endo_id, max_ribs);
	right_ribs = endo_back_right_ribs(endo_id, max_ribs);

	if (!single_cross_rib(left_ribs, right_ribs)) {
		dev_err(&hd->dev,
			"%s: More than one spanning rib (left 0x%02x right 0x%02x), id 0x%04x\n",
			__func__, left_ribs, right_ribs, endo_id);
		return false;
	}

	if (modules_oversized(max_ribs, left_ribs)) {
			dev_err(&hd->dev,
				"%s: Oversized module (left) 0x%02x, id 0x%04x\n",
				__func__, left_ribs, endo_id);
			return false;
	}

	if (modules_oversized(max_ribs, right_ribs)) {
			dev_err(&hd->dev,
				"%s: Oversized module (Right) 0x%02x, id 0x%04x\n",
				__func__, right_ribs, endo_id);
			return false;
	}

	/*
	 * The Endo numbering scheme represents the left and right rib
	 * configuration in a way that's convenient for looking for multiple
	 * spanning ribs.  But it doesn't match the normal Endo interface
	 * numbering scheme (increasing counter-clockwise around the back).
	 * Reverse the right bit positions so they do match.
	 */
	right_ribs = reverse_bits(right_ribs, max_ribs);

	/*
	 * A mini or large Endo rotated 180 degrees is still the same Endo.  In
	 * most cases that allows two distinct values to represent the same
	 * Endo; we choose one of them to be the canonical one (and the other is
	 * invalid).  The canonical one is identified by higher value of left
	 * ribs mask.
	 *
	 * This doesn't apply to medium Endos, because the left and right sides
	 * are of different widths.
	 */
	if (max_ribs != ENDO_BACK_RIBS_MEDIUM && left_ribs < right_ribs) {
		dev_err(&hd->dev, "%s: Non-canonical endo id 0x%04x\n", __func__,
			endo_id);
		return false;
	}

	layout->left_ribs = left_ribs;
	layout->right_ribs = right_ribs;
	return true;
}

/*
 * Validate the endo-id passed from SVC. Error out if its not a valid Endo,
 * else return structure representing ribs positions on front and back of Endo.
 */
static int gb_endo_validate_id(struct gb_host_device *hd,
			       struct endo_layout *layout, u16 endo_id)
{
	/* Validate Endo Size */
	if (endo_is_large(endo_id)) {
		/* Large Endo type */
		layout->max_ribs = ENDO_BACK_RIBS_LARGE;
	} else if (endo_is_medium(endo_id)) {
		/* Medium Endo type */
		layout->max_ribs = ENDO_BACK_RIBS_MEDIUM;
	} else if (endo_is_mini(endo_id)) {
		/* Mini Endo type */
		layout->max_ribs = ENDO_BACK_RIBS_MINI;
	} else {
		dev_err(&hd->dev, "%s: Invalid endo type, id 0x%04x\n",
			__func__, endo_id);
		return -EINVAL;
	}

	if (!validate_back_ribs(hd, layout, endo_id))
		return -EINVAL;

	if (!validate_front_ribs(hd, layout,
				 layout->max_ribs == ENDO_BACK_RIBS_MINI,
				 endo_id))
		return -EINVAL;

	return 0;
}

/*
 * Look up which module contains the given interface.
 *
 * A module's ID is the same as its lowest-numbered interface ID. So the module
 * ID for a 1x1 module is always the same as its interface ID.
 *
 * For Endo Back:
 * The module ID for an interface on a 1x2 or 2x2 module (which use two
 * interface blocks) can be either the interface ID, or one less than the
 * interface ID if there is no rib "above" the interface.
 *
 * For Endo Front:
 * There are three rib locations in front and all of them might be unused, i.e.
 * a single module is used for all 4 interfaces. We need to check all ribs in
 * that case to find module ID.
 */
u8 endo_get_module_id(struct gb_endo *endo, u8 interface_id)
{
	struct endo_layout *layout = &endo->layout;
	unsigned int height = layout->max_ribs + 1;
	unsigned int iid = interface_id - 1;
	unsigned int mask, rib_mask;

	if (!interface_id)
		return 0;

	if (iid < height) {			/* back left */
		mask = layout->left_ribs;
	} else if (iid < 2 * height) {	/* back right */
		mask = layout->right_ribs;
		iid -= height;
	} else {					/* front */
		mask = layout->front_ribs;
		iid -= 2 * height;
	}

	/*
	 * Find the next rib *above* this interface to determine the lowest
	 * interface ID in the module.
	 */
	rib_mask = 1 << iid;
	while ((rib_mask >>= 1) != 0 && !(mask & rib_mask))
		--interface_id;

	return interface_id;
}

/*
 * Creates all possible modules for the Endo.
 *
 * We try to create modules for all possible interface IDs. If a module is
 * already created, we skip creating it again with the help of prev_module_id.
 */
static int create_modules(struct gb_endo *endo)
{
	struct gb_module *module;
	int prev_module_id = 0;
	int interface_id;
	int module_id;
	int max_id;

	max_id = max_endo_interface_id(&endo->layout);

	/* Find module corresponding to each interface */
	for (interface_id = 1; interface_id <= max_id; interface_id++) {
		module_id = endo_get_module_id(endo, interface_id);

		if (WARN_ON(!module_id))
			continue;

		/* Skip already created modules */
		if (module_id == prev_module_id)
			continue;

		prev_module_id = module_id;

		/* New module, create it */
		module = gb_module_create(&endo->dev, module_id);
		if (!module)
			return -EINVAL;
	}

	return 0;
}

static int gb_endo_register(struct gb_host_device *hd,
			    struct gb_endo *endo)
{
	int dev_id;
	int retval;

	dev_id = ida_simple_get(&greybus_endo_id_map, 0, 0, GFP_KERNEL);
	if (dev_id < 0)
		return dev_id;

	endo->dev_id = dev_id;

	endo->dev.parent = &hd->dev;
	endo->dev.bus = &greybus_bus_type;
	endo->dev.type = &greybus_endo_type;
	endo->dev.groups = endo_groups;
	endo->dev.dma_mask = hd->dev.dma_mask;
	device_initialize(&endo->dev);
	dev_set_name(&endo->dev, "endo%hu", endo->dev_id);

	// FIXME
	// Get the version and serial number from the SVC, right now we are
	// using "fake" numbers.
	strcpy(&endo->svc_info.serial_number[0], "042");
	strcpy(&endo->svc_info.version[0], "0.0");

	retval = device_add(&endo->dev);
	if (retval) {
		dev_err(&hd->dev, "failed to add endo device of id 0x%04x\n",
			endo->id);
		put_device(&endo->dev);
	}

	return retval;
}

struct gb_endo *gb_endo_create(struct gb_host_device *hd, u16 endo_id,
				u8 ap_intf_id)
{
	struct gb_endo *endo;
	int retval;

	endo = kzalloc(sizeof(*endo), GFP_KERNEL);
	if (!endo)
		return ERR_PTR(-ENOMEM);

	/* First check if the value supplied is a valid endo id */
	if (gb_endo_validate_id(hd, &endo->layout, endo_id)) {
		retval = -EINVAL;
		goto free_endo;
	}
	if (ap_intf_id > max_endo_interface_id(&endo->layout)) {
		retval = -EINVAL;
		goto free_endo;
	}

	/* Register Endo device */
	retval = gb_endo_register(hd, endo);
	if (retval)
		goto free_endo;

	/* Create modules/interfaces */
	retval = create_modules(endo);
	if (retval) {
		gb_endo_remove(endo);
		return NULL;
	}

	return endo;

free_endo:
	kfree(endo);

	return ERR_PTR(retval);
}

void gb_endo_remove(struct gb_endo *endo)
{
	if (!endo)
		return;

	/* remove all modules for this endo */
	gb_module_remove_all(endo);

	device_unregister(&endo->dev);
}

int greybus_endo_setup(struct gb_host_device *hd, u16 endo_id,
		       u8 ap_intf_id)
{
	struct gb_endo *endo;

	endo = gb_endo_create(hd, endo_id, ap_intf_id);
	if (IS_ERR(endo))
		return PTR_ERR(endo);
	hd->endo = endo;

	return 0;
}
EXPORT_SYMBOL_GPL(greybus_endo_setup);

int __init gb_endo_init(void)
{
	ida_init(&greybus_endo_id_map);

	return 0;
}

void gb_endo_exit(void)
{
	ida_destroy(&greybus_endo_id_map);
}

drivers/staging/greybus/endo.h

deleted100644 → 0
+0 −63
Original line number Diff line number Diff line
/*
 * Greybus endo code
 *
 * Copyright 2015 Google Inc.
 * Copyright 2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#ifndef __ENDO_H
#define __ENDO_H

/* Greybus "public" definitions" */
struct gb_svc_info {
	u8 serial_number[10];
	u8 version[10];
};

/* Max ribs per Endo size */
#define ENDO_BACK_RIBS_MINI		0x4
#define ENDO_BACK_RIBS_MEDIUM		0x5
#define ENDO_BACK_RIBS_LARGE		0x6

/**
 * struct endo_layout - represents front/back ribs of the endo.
 *
 * @front_ribs:	Mask of present ribs in front.
 * @left_ribs:	Mask of present ribs in back (left).
 * @right_ribs:	Mask of present ribs in back (right).
 * @max_ribs:	Max ribs on endo back, possible values defined above.
 */
struct endo_layout {
	u8	front_ribs;
	u8	left_ribs;
	u8	right_ribs;
	u8	max_ribs;
};

struct gb_endo {
	struct device dev;
	struct endo_layout layout;
	struct gb_svc_info svc_info;
	u16 dev_id;
	u16 id;
	u8 ap_intf_id;
};
#define to_gb_endo(d) container_of(d, struct gb_endo, dev)

/* Greybus "private" definitions */
struct gb_host_device;

int gb_endo_init(void);
void gb_endo_exit(void);

struct gb_endo *gb_endo_create(struct gb_host_device *hd,
				u16 endo_id, u8 ap_intf_id);
void gb_endo_remove(struct gb_endo *endo);
int greybus_endo_setup(struct gb_host_device *hd, u16 endo_id,
		       u8 ap_intf_id);

u8 endo_get_module_id(struct gb_endo *endo, u8 interface_id);

#endif /* __ENDO_H */
+0 −14
Original line number Diff line number Diff line
@@ -26,10 +26,8 @@
#include "greybus_protocols.h"
#include "manifest.h"
#include "hd.h"
#include "endo.h"
#include "svc.h"
#include "firmware.h"
#include "module.h"
#include "control.h"
#include "interface.h"
#include "bundle.h"
@@ -105,8 +103,6 @@ struct dentry *gb_debugfs_get(void);
extern struct bus_type greybus_bus_type;

extern struct device_type greybus_hd_type;
extern struct device_type greybus_endo_type;
extern struct device_type greybus_module_type;
extern struct device_type greybus_interface_type;
extern struct device_type greybus_bundle_type;
extern struct device_type greybus_svc_type;
@@ -116,16 +112,6 @@ static inline int is_gb_host_device(const struct device *dev)
	return dev->type == &greybus_hd_type;
}

static inline int is_gb_endo(const struct device *dev)
{
	return dev->type == &greybus_endo_type;
}

static inline int is_gb_module(const struct device *dev)
{
	return dev->type == &greybus_module_type;
}

static inline int is_gb_interface(const struct device *dev)
{
	return dev->type == &greybus_interface_type;
Loading