blob: 885461598c94cd8595581447ab6dbfe10783f440 [file] [log] [blame]
Alex Elder8c12cde2014-10-01 21:54:12 -05001/*
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -05002 * Greybus bundles
Alex Elder8c12cde2014-10-01 21:54:12 -05003 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 Linaro Ltd.
Alex Elder8c12cde2014-10-01 21:54:12 -05006 *
7 * Released under the GPLv2 only.
8 */
9
10#include "greybus.h"
11
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050012static void gb_bundle_connections_exit(struct gb_bundle *bundle);
13static int gb_bundle_connections_init(struct gb_bundle *bundle);
14
15
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080016static ssize_t device_id_show(struct device *dev, struct device_attribute *attr,
17 char *buf)
18{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050019 struct gb_bundle *bundle = to_gb_bundle(dev);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080020
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050021 return sprintf(buf, "%d", bundle->device_id);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080022}
23static DEVICE_ATTR_RO(device_id);
24
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050025static struct attribute *bundle_attrs[] = {
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080026 &dev_attr_device_id.attr,
27 NULL,
28};
29
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050030ATTRIBUTE_GROUPS(bundle);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080031
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050032static void gb_bundle_release(struct device *dev)
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080033{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050034 struct gb_bundle *bundle = to_gb_bundle(dev);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080035
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050036 kfree(bundle);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080037}
38
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050039struct device_type greybus_bundle_type = {
40 .name = "greybus_bundle",
41 .release = gb_bundle_release,
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080042};
43
44
Alex Elder8c12cde2014-10-01 21:54:12 -050045/* XXX This could be per-host device or per-module */
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050046static DEFINE_SPINLOCK(gb_bundles_lock);
Alex Elder8c12cde2014-10-01 21:54:12 -050047
48/*
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050049 * Create a gb_bundle structure to represent a discovered
50 * bundle. Returns a pointer to the new bundle or a null
Alex Elder8c12cde2014-10-01 21:54:12 -050051 * pointer if a failure occurs due to memory exhaustion.
52 */
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050053struct gb_bundle *gb_bundle_create(struct gb_interface_block *gb_ib, u8 interface_id)
Alex Elder8c12cde2014-10-01 21:54:12 -050054{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050055 struct gb_bundle *bundle;
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080056 int retval;
Alex Elder8c12cde2014-10-01 21:54:12 -050057
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050058 bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
59 if (!bundle)
Alex Elder8c12cde2014-10-01 21:54:12 -050060 return NULL;
61
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050062 bundle->gb_ib = gb_ib;
63 bundle->id = interface_id;
64 bundle->device_id = 0xff; /* Invalid device id to start with */
65 INIT_LIST_HEAD(&bundle->connections);
Alex Elder8c12cde2014-10-01 21:54:12 -050066
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050067 /* Build up the bundle device structures and register it with the
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080068 * driver core */
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050069 bundle->dev.parent = &gb_ib->dev;
70 bundle->dev.bus = &greybus_bus_type;
71 bundle->dev.type = &greybus_bundle_type;
72 bundle->dev.groups = bundle_groups;
73 device_initialize(&bundle->dev);
74 dev_set_name(&bundle->dev, "%d:%d", gb_ib->module_id, interface_id);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080075
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050076 retval = device_add(&bundle->dev);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080077 if (retval) {
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050078 pr_err("failed to add bundle device for id 0x%02hhx\n",
Alex Elder6b099382014-11-05 16:03:12 -060079 interface_id);
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050080 put_device(&bundle->dev);
81 kfree(bundle);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080082 return NULL;
83 }
84
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050085 spin_lock_irq(&gb_bundles_lock);
86 list_add_tail(&bundle->links, &gb_ib->interfaces);
87 spin_unlock_irq(&gb_bundles_lock);
Alex Elder8c12cde2014-10-01 21:54:12 -050088
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050089 return bundle;
Alex Elder8c12cde2014-10-01 21:54:12 -050090}
91
92/*
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050093 * Tear down a previously set up bundle.
Alex Elder8c12cde2014-10-01 21:54:12 -050094 */
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050095void gb_bundle_destroy(struct gb_interface_block *gb_ib)
Alex Elder8c12cde2014-10-01 21:54:12 -050096{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -050097 struct gb_bundle *bundle;
98 struct gb_bundle *temp;
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +080099
Greg Kroah-Hartman4ec7b072014-12-11 17:10:56 -0500100 if (WARN_ON(!gb_ib))
Alex Elder8c12cde2014-10-01 21:54:12 -0500101 return;
102
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500103 spin_lock_irq(&gb_bundles_lock);
104 list_for_each_entry_safe(bundle, temp, &gb_ib->interfaces, links) {
105 list_del(&bundle->links);
106 gb_bundle_connections_exit(bundle);
107 device_del(&bundle->dev);
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800108 }
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500109 spin_unlock_irq(&gb_bundles_lock);
Alex Elder8c12cde2014-10-01 21:54:12 -0500110}
Alex Elder574341c2014-10-16 06:35:35 -0500111
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500112int gb_bundle_init(struct gb_interface_block *gb_ib, u8 bundle_id, u8 device_id)
Viresh Kumar2206ea92014-11-14 17:25:08 +0530113{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500114 struct gb_bundle *bundle;
Viresh Kumar2206ea92014-11-14 17:25:08 +0530115 int ret;
116
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500117 bundle = gb_bundle_find(gb_ib, bundle_id);
118 if (!bundle) {
119 dev_err(gb_ib->hd->parent, "bundle %hhu not found\n",
120 bundle_id);
Viresh Kumar2206ea92014-11-14 17:25:08 +0530121 return -ENOENT;
122 }
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500123 bundle->device_id = device_id;
Viresh Kumar2206ea92014-11-14 17:25:08 +0530124
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500125 ret = svc_set_route_send(bundle, gb_ib->hd);
Viresh Kumar2206ea92014-11-14 17:25:08 +0530126 if (ret) {
Greg Kroah-Hartman4ec7b072014-12-11 17:10:56 -0500127 dev_err(gb_ib->hd->parent, "failed to set route (%d)\n", ret);
Viresh Kumar2206ea92014-11-14 17:25:08 +0530128 return ret;
129 }
130
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500131 ret = gb_bundle_connections_init(bundle);
Viresh Kumar2206ea92014-11-14 17:25:08 +0530132 if (ret) {
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500133 dev_err(gb_ib->hd->parent, "interface bundle init error %d\n",
Viresh Kumar2206ea92014-11-14 17:25:08 +0530134 ret);
135 /* XXX clear route */
136 return ret;
137 }
138
139 return 0;
140}
141
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500142struct gb_bundle *gb_bundle_find(struct gb_interface_block *gb_ib, u8 bundle_id)
Matt Porter1a4c0132014-10-21 22:43:30 -0400143{
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500144 struct gb_bundle *bundle;
Matt Porter1a4c0132014-10-21 22:43:30 -0400145
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500146 spin_lock_irq(&gb_bundles_lock);
147 list_for_each_entry(bundle, &gb_ib->interfaces, links)
148 if (bundle->id == bundle_id) {
149 spin_unlock_irq(&gb_bundles_lock);
150 return bundle;
Greg Kroah-Hartmanf0f61b92014-10-24 17:34:46 +0800151 }
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500152 spin_unlock_irq(&gb_bundles_lock);
Matt Porter1a4c0132014-10-21 22:43:30 -0400153
154 return NULL;
155}
156
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500157static int gb_bundle_connections_init(struct gb_bundle *bundle)
Alex Elder574341c2014-10-16 06:35:35 -0500158{
159 struct gb_connection *connection;
160 int ret = 0;
161
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500162 list_for_each_entry(connection, &bundle->connections, bundle_links) {
Alex Elder574341c2014-10-16 06:35:35 -0500163 ret = gb_connection_init(connection);
164 if (ret)
165 break;
166 }
167
168 return ret;
169}
Alex Elder697e55d2014-10-20 23:01:04 -0500170
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500171static void gb_bundle_connections_exit(struct gb_bundle *bundle)
Alex Elder697e55d2014-10-20 23:01:04 -0500172{
173 struct gb_connection *connection;
174 struct gb_connection *next;
175
Greg Kroah-Hartman1db0a5f2014-12-12 17:10:17 -0500176 list_for_each_entry_safe(connection, next, &bundle->connections,
177 bundle_links) {
Alex Elder697e55d2014-10-20 23:01:04 -0500178 gb_connection_exit(connection);
179 gb_connection_destroy(connection);
180 }
181}