xref: /linux/drivers/most/core.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1b2765275SChristian Gromm // SPDX-License-Identifier: GPL-2.0
2b2765275SChristian Gromm /*
3b2765275SChristian Gromm  * core.c - Implementation of core module of MOST Linux driver stack
4b2765275SChristian Gromm  *
5b2765275SChristian Gromm  * Copyright (C) 2013-2020 Microchip Technology Germany II GmbH & Co. KG
6b2765275SChristian Gromm  */
7b2765275SChristian Gromm 
8b2765275SChristian Gromm #include <linux/module.h>
9b2765275SChristian Gromm #include <linux/fs.h>
10b2765275SChristian Gromm #include <linux/slab.h>
11b2765275SChristian Gromm #include <linux/init.h>
12b2765275SChristian Gromm #include <linux/device.h>
13b2765275SChristian Gromm #include <linux/list.h>
14b2765275SChristian Gromm #include <linux/poll.h>
15b2765275SChristian Gromm #include <linux/wait.h>
16b2765275SChristian Gromm #include <linux/kobject.h>
17b2765275SChristian Gromm #include <linux/mutex.h>
18b2765275SChristian Gromm #include <linux/completion.h>
19b2765275SChristian Gromm #include <linux/sysfs.h>
20b2765275SChristian Gromm #include <linux/kthread.h>
21b2765275SChristian Gromm #include <linux/dma-mapping.h>
22b2765275SChristian Gromm #include <linux/idr.h>
23b2765275SChristian Gromm #include <linux/most.h>
24b2765275SChristian Gromm 
25b2765275SChristian Gromm #define MAX_CHANNELS	64
26b2765275SChristian Gromm #define STRING_SIZE	80
27b2765275SChristian Gromm 
28b2765275SChristian Gromm static struct ida mdev_id;
29b2765275SChristian Gromm static int dummy_num_buffers;
30b2765275SChristian Gromm static struct list_head comp_list;
31b2765275SChristian Gromm 
32b2765275SChristian Gromm struct pipe {
33b2765275SChristian Gromm 	struct most_component *comp;
34b2765275SChristian Gromm 	int refs;
35b2765275SChristian Gromm 	int num_buffers;
36b2765275SChristian Gromm };
37b2765275SChristian Gromm 
38b2765275SChristian Gromm struct most_channel {
39b2765275SChristian Gromm 	struct device dev;
40b2765275SChristian Gromm 	struct completion cleanup;
41b2765275SChristian Gromm 	atomic_t mbo_ref;
42b2765275SChristian Gromm 	atomic_t mbo_nq_level;
43b2765275SChristian Gromm 	u16 channel_id;
44b2765275SChristian Gromm 	char name[STRING_SIZE];
45b2765275SChristian Gromm 	bool is_poisoned;
46b2765275SChristian Gromm 	struct mutex start_mutex; /* channel activation synchronization */
47b2765275SChristian Gromm 	struct mutex nq_mutex; /* nq thread synchronization */
48b2765275SChristian Gromm 	int is_starving;
49b2765275SChristian Gromm 	struct most_interface *iface;
50b2765275SChristian Gromm 	struct most_channel_config cfg;
51b2765275SChristian Gromm 	bool keep_mbo;
52b2765275SChristian Gromm 	bool enqueue_halt;
53b2765275SChristian Gromm 	struct list_head fifo;
54b2765275SChristian Gromm 	spinlock_t fifo_lock; /* fifo access synchronization */
55b2765275SChristian Gromm 	struct list_head halt_fifo;
56b2765275SChristian Gromm 	struct list_head list;
57b2765275SChristian Gromm 	struct pipe pipe0;
58b2765275SChristian Gromm 	struct pipe pipe1;
59b2765275SChristian Gromm 	struct list_head trash_fifo;
60b2765275SChristian Gromm 	struct task_struct *hdm_enqueue_task;
61b2765275SChristian Gromm 	wait_queue_head_t hdm_fifo_wq;
62b2765275SChristian Gromm 
63b2765275SChristian Gromm };
64b2765275SChristian Gromm 
65b2765275SChristian Gromm #define to_channel(d) container_of(d, struct most_channel, dev)
66b2765275SChristian Gromm 
67b2765275SChristian Gromm struct interface_private {
68b2765275SChristian Gromm 	int dev_id;
69b2765275SChristian Gromm 	char name[STRING_SIZE];
70b2765275SChristian Gromm 	struct most_channel *channel[MAX_CHANNELS];
71b2765275SChristian Gromm 	struct list_head channel_list;
72b2765275SChristian Gromm };
73b2765275SChristian Gromm 
74b2765275SChristian Gromm static const struct {
75b2765275SChristian Gromm 	int most_ch_data_type;
76b2765275SChristian Gromm 	const char *name;
77b2765275SChristian Gromm } ch_data_type[] = {
78b2765275SChristian Gromm 	{ MOST_CH_CONTROL, "control" },
79b2765275SChristian Gromm 	{ MOST_CH_ASYNC, "async" },
80b2765275SChristian Gromm 	{ MOST_CH_SYNC, "sync" },
81b2765275SChristian Gromm 	{ MOST_CH_ISOC, "isoc"},
82b2765275SChristian Gromm 	{ MOST_CH_ISOC, "isoc_avp"},
83b2765275SChristian Gromm };
84b2765275SChristian Gromm 
85b2765275SChristian Gromm /**
86b2765275SChristian Gromm  * list_pop_mbo - retrieves the first MBO of the list and removes it
87b2765275SChristian Gromm  * @ptr: the list head to grab the MBO from.
88b2765275SChristian Gromm  */
89b2765275SChristian Gromm #define list_pop_mbo(ptr)						\
90b2765275SChristian Gromm ({									\
91b2765275SChristian Gromm 	struct mbo *_mbo = list_first_entry(ptr, struct mbo, list);	\
92b2765275SChristian Gromm 	list_del(&_mbo->list);						\
93b2765275SChristian Gromm 	_mbo;								\
94b2765275SChristian Gromm })
95b2765275SChristian Gromm 
96b2765275SChristian Gromm /**
97b2765275SChristian Gromm  * most_free_mbo_coherent - free an MBO and its coherent buffer
98b2765275SChristian Gromm  * @mbo: most buffer
99b2765275SChristian Gromm  */
most_free_mbo_coherent(struct mbo * mbo)100b2765275SChristian Gromm static void most_free_mbo_coherent(struct mbo *mbo)
101b2765275SChristian Gromm {
102b2765275SChristian Gromm 	struct most_channel *c = mbo->context;
103b2765275SChristian Gromm 	u16 const coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len;
104b2765275SChristian Gromm 
105b2765275SChristian Gromm 	if (c->iface->dma_free)
106b2765275SChristian Gromm 		c->iface->dma_free(mbo, coherent_buf_size);
107b2765275SChristian Gromm 	else
108b2765275SChristian Gromm 		kfree(mbo->virt_address);
109b2765275SChristian Gromm 	kfree(mbo);
110b2765275SChristian Gromm 	if (atomic_sub_and_test(1, &c->mbo_ref))
111b2765275SChristian Gromm 		complete(&c->cleanup);
112b2765275SChristian Gromm }
113b2765275SChristian Gromm 
114b2765275SChristian Gromm /**
115b2765275SChristian Gromm  * flush_channel_fifos - clear the channel fifos
116b2765275SChristian Gromm  * @c: pointer to channel object
117b2765275SChristian Gromm  */
flush_channel_fifos(struct most_channel * c)118b2765275SChristian Gromm static void flush_channel_fifos(struct most_channel *c)
119b2765275SChristian Gromm {
120b2765275SChristian Gromm 	unsigned long flags, hf_flags;
121b2765275SChristian Gromm 	struct mbo *mbo, *tmp;
122b2765275SChristian Gromm 
123b2765275SChristian Gromm 	if (list_empty(&c->fifo) && list_empty(&c->halt_fifo))
124b2765275SChristian Gromm 		return;
125b2765275SChristian Gromm 
126b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
127b2765275SChristian Gromm 	list_for_each_entry_safe(mbo, tmp, &c->fifo, list) {
128b2765275SChristian Gromm 		list_del(&mbo->list);
129b2765275SChristian Gromm 		spin_unlock_irqrestore(&c->fifo_lock, flags);
130b2765275SChristian Gromm 		most_free_mbo_coherent(mbo);
131b2765275SChristian Gromm 		spin_lock_irqsave(&c->fifo_lock, flags);
132b2765275SChristian Gromm 	}
133b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
134b2765275SChristian Gromm 
135b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, hf_flags);
136b2765275SChristian Gromm 	list_for_each_entry_safe(mbo, tmp, &c->halt_fifo, list) {
137b2765275SChristian Gromm 		list_del(&mbo->list);
138b2765275SChristian Gromm 		spin_unlock_irqrestore(&c->fifo_lock, hf_flags);
139b2765275SChristian Gromm 		most_free_mbo_coherent(mbo);
140b2765275SChristian Gromm 		spin_lock_irqsave(&c->fifo_lock, hf_flags);
141b2765275SChristian Gromm 	}
142b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, hf_flags);
143b2765275SChristian Gromm 
144b2765275SChristian Gromm 	if (unlikely((!list_empty(&c->fifo) || !list_empty(&c->halt_fifo))))
145b2765275SChristian Gromm 		dev_warn(&c->dev, "Channel or trash fifo not empty\n");
146b2765275SChristian Gromm }
147b2765275SChristian Gromm 
148b2765275SChristian Gromm /**
149b2765275SChristian Gromm  * flush_trash_fifo - clear the trash fifo
150b2765275SChristian Gromm  * @c: pointer to channel object
151b2765275SChristian Gromm  */
flush_trash_fifo(struct most_channel * c)152b2765275SChristian Gromm static int flush_trash_fifo(struct most_channel *c)
153b2765275SChristian Gromm {
154b2765275SChristian Gromm 	struct mbo *mbo, *tmp;
155b2765275SChristian Gromm 	unsigned long flags;
156b2765275SChristian Gromm 
157b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
158b2765275SChristian Gromm 	list_for_each_entry_safe(mbo, tmp, &c->trash_fifo, list) {
159b2765275SChristian Gromm 		list_del(&mbo->list);
160b2765275SChristian Gromm 		spin_unlock_irqrestore(&c->fifo_lock, flags);
161b2765275SChristian Gromm 		most_free_mbo_coherent(mbo);
162b2765275SChristian Gromm 		spin_lock_irqsave(&c->fifo_lock, flags);
163b2765275SChristian Gromm 	}
164b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
165b2765275SChristian Gromm 	return 0;
166b2765275SChristian Gromm }
167b2765275SChristian Gromm 
available_directions_show(struct device * dev,struct device_attribute * attr,char * buf)168b2765275SChristian Gromm static ssize_t available_directions_show(struct device *dev,
169b2765275SChristian Gromm 					 struct device_attribute *attr,
170b2765275SChristian Gromm 					 char *buf)
171b2765275SChristian Gromm {
172b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
173b2765275SChristian Gromm 	unsigned int i = c->channel_id;
174b2765275SChristian Gromm 
175b2765275SChristian Gromm 	strcpy(buf, "");
176b2765275SChristian Gromm 	if (c->iface->channel_vector[i].direction & MOST_CH_RX)
177b2765275SChristian Gromm 		strcat(buf, "rx ");
178b2765275SChristian Gromm 	if (c->iface->channel_vector[i].direction & MOST_CH_TX)
179b2765275SChristian Gromm 		strcat(buf, "tx ");
180b2765275SChristian Gromm 	strcat(buf, "\n");
181b2765275SChristian Gromm 	return strlen(buf);
182b2765275SChristian Gromm }
183b2765275SChristian Gromm 
available_datatypes_show(struct device * dev,struct device_attribute * attr,char * buf)184b2765275SChristian Gromm static ssize_t available_datatypes_show(struct device *dev,
185b2765275SChristian Gromm 					struct device_attribute *attr,
186b2765275SChristian Gromm 					char *buf)
187b2765275SChristian Gromm {
188b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
189b2765275SChristian Gromm 	unsigned int i = c->channel_id;
190b2765275SChristian Gromm 
191b2765275SChristian Gromm 	strcpy(buf, "");
192b2765275SChristian Gromm 	if (c->iface->channel_vector[i].data_type & MOST_CH_CONTROL)
193b2765275SChristian Gromm 		strcat(buf, "control ");
194b2765275SChristian Gromm 	if (c->iface->channel_vector[i].data_type & MOST_CH_ASYNC)
195b2765275SChristian Gromm 		strcat(buf, "async ");
196b2765275SChristian Gromm 	if (c->iface->channel_vector[i].data_type & MOST_CH_SYNC)
197b2765275SChristian Gromm 		strcat(buf, "sync ");
198b2765275SChristian Gromm 	if (c->iface->channel_vector[i].data_type & MOST_CH_ISOC)
199b2765275SChristian Gromm 		strcat(buf, "isoc ");
200b2765275SChristian Gromm 	strcat(buf, "\n");
201b2765275SChristian Gromm 	return strlen(buf);
202b2765275SChristian Gromm }
203b2765275SChristian Gromm 
number_of_packet_buffers_show(struct device * dev,struct device_attribute * attr,char * buf)204b2765275SChristian Gromm static ssize_t number_of_packet_buffers_show(struct device *dev,
205b2765275SChristian Gromm 					     struct device_attribute *attr,
206b2765275SChristian Gromm 					     char *buf)
207b2765275SChristian Gromm {
208b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
209b2765275SChristian Gromm 	unsigned int i = c->channel_id;
210b2765275SChristian Gromm 
211b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n",
212b2765275SChristian Gromm 			c->iface->channel_vector[i].num_buffers_packet);
213b2765275SChristian Gromm }
214b2765275SChristian Gromm 
number_of_stream_buffers_show(struct device * dev,struct device_attribute * attr,char * buf)215b2765275SChristian Gromm static ssize_t number_of_stream_buffers_show(struct device *dev,
216b2765275SChristian Gromm 					     struct device_attribute *attr,
217b2765275SChristian Gromm 					     char *buf)
218b2765275SChristian Gromm {
219b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
220b2765275SChristian Gromm 	unsigned int i = c->channel_id;
221b2765275SChristian Gromm 
222b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n",
223b2765275SChristian Gromm 			c->iface->channel_vector[i].num_buffers_streaming);
224b2765275SChristian Gromm }
225b2765275SChristian Gromm 
size_of_packet_buffer_show(struct device * dev,struct device_attribute * attr,char * buf)226b2765275SChristian Gromm static ssize_t size_of_packet_buffer_show(struct device *dev,
227b2765275SChristian Gromm 					  struct device_attribute *attr,
228b2765275SChristian Gromm 					  char *buf)
229b2765275SChristian Gromm {
230b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
231b2765275SChristian Gromm 	unsigned int i = c->channel_id;
232b2765275SChristian Gromm 
233b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n",
234b2765275SChristian Gromm 			c->iface->channel_vector[i].buffer_size_packet);
235b2765275SChristian Gromm }
236b2765275SChristian Gromm 
size_of_stream_buffer_show(struct device * dev,struct device_attribute * attr,char * buf)237b2765275SChristian Gromm static ssize_t size_of_stream_buffer_show(struct device *dev,
238b2765275SChristian Gromm 					  struct device_attribute *attr,
239b2765275SChristian Gromm 					  char *buf)
240b2765275SChristian Gromm {
241b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
242b2765275SChristian Gromm 	unsigned int i = c->channel_id;
243b2765275SChristian Gromm 
244b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n",
245b2765275SChristian Gromm 			c->iface->channel_vector[i].buffer_size_streaming);
246b2765275SChristian Gromm }
247b2765275SChristian Gromm 
channel_starving_show(struct device * dev,struct device_attribute * attr,char * buf)248b2765275SChristian Gromm static ssize_t channel_starving_show(struct device *dev,
249b2765275SChristian Gromm 				     struct device_attribute *attr,
250b2765275SChristian Gromm 				     char *buf)
251b2765275SChristian Gromm {
252b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
253b2765275SChristian Gromm 
254b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->is_starving);
255b2765275SChristian Gromm }
256b2765275SChristian Gromm 
set_number_of_buffers_show(struct device * dev,struct device_attribute * attr,char * buf)257b2765275SChristian Gromm static ssize_t set_number_of_buffers_show(struct device *dev,
258b2765275SChristian Gromm 					  struct device_attribute *attr,
259b2765275SChristian Gromm 					  char *buf)
260b2765275SChristian Gromm {
261b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
262b2765275SChristian Gromm 
263b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.num_buffers);
264b2765275SChristian Gromm }
265b2765275SChristian Gromm 
set_buffer_size_show(struct device * dev,struct device_attribute * attr,char * buf)266b2765275SChristian Gromm static ssize_t set_buffer_size_show(struct device *dev,
267b2765275SChristian Gromm 				    struct device_attribute *attr,
268b2765275SChristian Gromm 				    char *buf)
269b2765275SChristian Gromm {
270b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
271b2765275SChristian Gromm 
272b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.buffer_size);
273b2765275SChristian Gromm }
274b2765275SChristian Gromm 
set_direction_show(struct device * dev,struct device_attribute * attr,char * buf)275b2765275SChristian Gromm static ssize_t set_direction_show(struct device *dev,
276b2765275SChristian Gromm 				  struct device_attribute *attr,
277b2765275SChristian Gromm 				  char *buf)
278b2765275SChristian Gromm {
279b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
280b2765275SChristian Gromm 
281b2765275SChristian Gromm 	if (c->cfg.direction & MOST_CH_TX)
282b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "tx\n");
283b2765275SChristian Gromm 	else if (c->cfg.direction & MOST_CH_RX)
284b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "rx\n");
285b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "unconfigured\n");
286b2765275SChristian Gromm }
287b2765275SChristian Gromm 
set_datatype_show(struct device * dev,struct device_attribute * attr,char * buf)288b2765275SChristian Gromm static ssize_t set_datatype_show(struct device *dev,
289b2765275SChristian Gromm 				 struct device_attribute *attr,
290b2765275SChristian Gromm 				 char *buf)
291b2765275SChristian Gromm {
292b2765275SChristian Gromm 	int i;
293b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
294b2765275SChristian Gromm 
295b2765275SChristian Gromm 	for (i = 0; i < ARRAY_SIZE(ch_data_type); i++) {
296b2765275SChristian Gromm 		if (c->cfg.data_type & ch_data_type[i].most_ch_data_type)
297b2765275SChristian Gromm 			return snprintf(buf, PAGE_SIZE, "%s",
298b2765275SChristian Gromm 					ch_data_type[i].name);
299b2765275SChristian Gromm 	}
300b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "unconfigured\n");
301b2765275SChristian Gromm }
302b2765275SChristian Gromm 
set_subbuffer_size_show(struct device * dev,struct device_attribute * attr,char * buf)303b2765275SChristian Gromm static ssize_t set_subbuffer_size_show(struct device *dev,
304b2765275SChristian Gromm 				       struct device_attribute *attr,
305b2765275SChristian Gromm 				       char *buf)
306b2765275SChristian Gromm {
307b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
308b2765275SChristian Gromm 
309b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.subbuffer_size);
310b2765275SChristian Gromm }
311b2765275SChristian Gromm 
set_packets_per_xact_show(struct device * dev,struct device_attribute * attr,char * buf)312b2765275SChristian Gromm static ssize_t set_packets_per_xact_show(struct device *dev,
313b2765275SChristian Gromm 					 struct device_attribute *attr,
314b2765275SChristian Gromm 					 char *buf)
315b2765275SChristian Gromm {
316b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
317b2765275SChristian Gromm 
318b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.packets_per_xact);
319b2765275SChristian Gromm }
320b2765275SChristian Gromm 
set_dbr_size_show(struct device * dev,struct device_attribute * attr,char * buf)321b2765275SChristian Gromm static ssize_t set_dbr_size_show(struct device *dev,
322b2765275SChristian Gromm 				 struct device_attribute *attr, char *buf)
323b2765275SChristian Gromm {
324b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
325b2765275SChristian Gromm 
326b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.dbr_size);
327b2765275SChristian Gromm }
328b2765275SChristian Gromm 
329b2765275SChristian Gromm #define to_dev_attr(a) container_of(a, struct device_attribute, attr)
channel_attr_is_visible(struct kobject * kobj,struct attribute * attr,int index)330b2765275SChristian Gromm static umode_t channel_attr_is_visible(struct kobject *kobj,
331b2765275SChristian Gromm 				       struct attribute *attr, int index)
332b2765275SChristian Gromm {
333b2765275SChristian Gromm 	struct device_attribute *dev_attr = to_dev_attr(attr);
334b2765275SChristian Gromm 	struct device *dev = kobj_to_dev(kobj);
335b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
336b2765275SChristian Gromm 
337b2765275SChristian Gromm 	if (!strcmp(dev_attr->attr.name, "set_dbr_size") &&
338b2765275SChristian Gromm 	    (c->iface->interface != ITYPE_MEDIALB_DIM2))
339b2765275SChristian Gromm 		return 0;
340b2765275SChristian Gromm 	if (!strcmp(dev_attr->attr.name, "set_packets_per_xact") &&
341b2765275SChristian Gromm 	    (c->iface->interface != ITYPE_USB))
342b2765275SChristian Gromm 		return 0;
343b2765275SChristian Gromm 
344b2765275SChristian Gromm 	return attr->mode;
345b2765275SChristian Gromm }
346b2765275SChristian Gromm 
347b2765275SChristian Gromm #define DEV_ATTR(_name)  (&dev_attr_##_name.attr)
348b2765275SChristian Gromm 
349b2765275SChristian Gromm static DEVICE_ATTR_RO(available_directions);
350b2765275SChristian Gromm static DEVICE_ATTR_RO(available_datatypes);
351b2765275SChristian Gromm static DEVICE_ATTR_RO(number_of_packet_buffers);
352b2765275SChristian Gromm static DEVICE_ATTR_RO(number_of_stream_buffers);
353b2765275SChristian Gromm static DEVICE_ATTR_RO(size_of_stream_buffer);
354b2765275SChristian Gromm static DEVICE_ATTR_RO(size_of_packet_buffer);
355b2765275SChristian Gromm static DEVICE_ATTR_RO(channel_starving);
356b2765275SChristian Gromm static DEVICE_ATTR_RO(set_buffer_size);
357b2765275SChristian Gromm static DEVICE_ATTR_RO(set_number_of_buffers);
358b2765275SChristian Gromm static DEVICE_ATTR_RO(set_direction);
359b2765275SChristian Gromm static DEVICE_ATTR_RO(set_datatype);
360b2765275SChristian Gromm static DEVICE_ATTR_RO(set_subbuffer_size);
361b2765275SChristian Gromm static DEVICE_ATTR_RO(set_packets_per_xact);
362b2765275SChristian Gromm static DEVICE_ATTR_RO(set_dbr_size);
363b2765275SChristian Gromm 
364b2765275SChristian Gromm static struct attribute *channel_attrs[] = {
365b2765275SChristian Gromm 	DEV_ATTR(available_directions),
366b2765275SChristian Gromm 	DEV_ATTR(available_datatypes),
367b2765275SChristian Gromm 	DEV_ATTR(number_of_packet_buffers),
368b2765275SChristian Gromm 	DEV_ATTR(number_of_stream_buffers),
369b2765275SChristian Gromm 	DEV_ATTR(size_of_stream_buffer),
370b2765275SChristian Gromm 	DEV_ATTR(size_of_packet_buffer),
371b2765275SChristian Gromm 	DEV_ATTR(channel_starving),
372b2765275SChristian Gromm 	DEV_ATTR(set_buffer_size),
373b2765275SChristian Gromm 	DEV_ATTR(set_number_of_buffers),
374b2765275SChristian Gromm 	DEV_ATTR(set_direction),
375b2765275SChristian Gromm 	DEV_ATTR(set_datatype),
376b2765275SChristian Gromm 	DEV_ATTR(set_subbuffer_size),
377b2765275SChristian Gromm 	DEV_ATTR(set_packets_per_xact),
378b2765275SChristian Gromm 	DEV_ATTR(set_dbr_size),
379b2765275SChristian Gromm 	NULL,
380b2765275SChristian Gromm };
381b2765275SChristian Gromm 
38226c2e922SRikard Falkeborn static const struct attribute_group channel_attr_group = {
383b2765275SChristian Gromm 	.attrs = channel_attrs,
384b2765275SChristian Gromm 	.is_visible = channel_attr_is_visible,
385b2765275SChristian Gromm };
386b2765275SChristian Gromm 
387b2765275SChristian Gromm static const struct attribute_group *channel_attr_groups[] = {
388b2765275SChristian Gromm 	&channel_attr_group,
389b2765275SChristian Gromm 	NULL,
390b2765275SChristian Gromm };
391b2765275SChristian Gromm 
description_show(struct device * dev,struct device_attribute * attr,char * buf)392b2765275SChristian Gromm static ssize_t description_show(struct device *dev,
393b2765275SChristian Gromm 				struct device_attribute *attr,
394b2765275SChristian Gromm 				char *buf)
395b2765275SChristian Gromm {
396b2765275SChristian Gromm 	struct most_interface *iface = dev_get_drvdata(dev);
397b2765275SChristian Gromm 
398b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "%s\n", iface->description);
399b2765275SChristian Gromm }
400b2765275SChristian Gromm 
interface_show(struct device * dev,struct device_attribute * attr,char * buf)401b2765275SChristian Gromm static ssize_t interface_show(struct device *dev,
402b2765275SChristian Gromm 			      struct device_attribute *attr,
403b2765275SChristian Gromm 			      char *buf)
404b2765275SChristian Gromm {
405b2765275SChristian Gromm 	struct most_interface *iface = dev_get_drvdata(dev);
406b2765275SChristian Gromm 
407b2765275SChristian Gromm 	switch (iface->interface) {
408b2765275SChristian Gromm 	case ITYPE_LOOPBACK:
409b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "loopback\n");
410b2765275SChristian Gromm 	case ITYPE_I2C:
411b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "i2c\n");
412b2765275SChristian Gromm 	case ITYPE_I2S:
413b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "i2s\n");
414b2765275SChristian Gromm 	case ITYPE_TSI:
415b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "tsi\n");
416b2765275SChristian Gromm 	case ITYPE_HBI:
417b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "hbi\n");
418b2765275SChristian Gromm 	case ITYPE_MEDIALB_DIM:
419b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "mlb_dim\n");
420b2765275SChristian Gromm 	case ITYPE_MEDIALB_DIM2:
421b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "mlb_dim2\n");
422b2765275SChristian Gromm 	case ITYPE_USB:
423b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "usb\n");
424b2765275SChristian Gromm 	case ITYPE_PCIE:
425b2765275SChristian Gromm 		return snprintf(buf, PAGE_SIZE, "pcie\n");
426b2765275SChristian Gromm 	}
427b2765275SChristian Gromm 	return snprintf(buf, PAGE_SIZE, "unknown\n");
428b2765275SChristian Gromm }
429b2765275SChristian Gromm 
430b2765275SChristian Gromm static DEVICE_ATTR_RO(description);
431b2765275SChristian Gromm static DEVICE_ATTR_RO(interface);
432b2765275SChristian Gromm 
433b2765275SChristian Gromm static struct attribute *interface_attrs[] = {
434b2765275SChristian Gromm 	DEV_ATTR(description),
435b2765275SChristian Gromm 	DEV_ATTR(interface),
436b2765275SChristian Gromm 	NULL,
437b2765275SChristian Gromm };
438b2765275SChristian Gromm 
43926c2e922SRikard Falkeborn static const struct attribute_group interface_attr_group = {
440b2765275SChristian Gromm 	.attrs = interface_attrs,
441b2765275SChristian Gromm };
442b2765275SChristian Gromm 
443b2765275SChristian Gromm static const struct attribute_group *interface_attr_groups[] = {
444b2765275SChristian Gromm 	&interface_attr_group,
445b2765275SChristian Gromm 	NULL,
446b2765275SChristian Gromm };
447b2765275SChristian Gromm 
match_component(char * name)448b2765275SChristian Gromm static struct most_component *match_component(char *name)
449b2765275SChristian Gromm {
450b2765275SChristian Gromm 	struct most_component *comp;
451b2765275SChristian Gromm 
452b2765275SChristian Gromm 	list_for_each_entry(comp, &comp_list, list) {
453b2765275SChristian Gromm 		if (!strcmp(comp->name, name))
454b2765275SChristian Gromm 			return comp;
455b2765275SChristian Gromm 	}
456b2765275SChristian Gromm 	return NULL;
457b2765275SChristian Gromm }
458b2765275SChristian Gromm 
459b2765275SChristian Gromm struct show_links_data {
460b2765275SChristian Gromm 	int offs;
461b2765275SChristian Gromm 	char *buf;
462b2765275SChristian Gromm };
463b2765275SChristian Gromm 
print_links(struct device * dev,void * data)464b2765275SChristian Gromm static int print_links(struct device *dev, void *data)
465b2765275SChristian Gromm {
466b2765275SChristian Gromm 	struct show_links_data *d = data;
467b2765275SChristian Gromm 	int offs = d->offs;
468b2765275SChristian Gromm 	char *buf = d->buf;
469b2765275SChristian Gromm 	struct most_channel *c;
470b2765275SChristian Gromm 	struct most_interface *iface = dev_get_drvdata(dev);
471b2765275SChristian Gromm 
472b2765275SChristian Gromm 	list_for_each_entry(c, &iface->p->channel_list, list) {
473b2765275SChristian Gromm 		if (c->pipe0.comp) {
474b2765275SChristian Gromm 			offs += scnprintf(buf + offs,
475b2765275SChristian Gromm 					 PAGE_SIZE - offs,
476b2765275SChristian Gromm 					 "%s:%s:%s\n",
477b2765275SChristian Gromm 					 c->pipe0.comp->name,
478b2765275SChristian Gromm 					 dev_name(iface->dev),
479b2765275SChristian Gromm 					 dev_name(&c->dev));
480b2765275SChristian Gromm 		}
481b2765275SChristian Gromm 		if (c->pipe1.comp) {
482b2765275SChristian Gromm 			offs += scnprintf(buf + offs,
483b2765275SChristian Gromm 					 PAGE_SIZE - offs,
484b2765275SChristian Gromm 					 "%s:%s:%s\n",
485b2765275SChristian Gromm 					 c->pipe1.comp->name,
486b2765275SChristian Gromm 					 dev_name(iface->dev),
487b2765275SChristian Gromm 					 dev_name(&c->dev));
488b2765275SChristian Gromm 		}
489b2765275SChristian Gromm 	}
490b2765275SChristian Gromm 	d->offs = offs;
491b2765275SChristian Gromm 	return 0;
492b2765275SChristian Gromm }
493b2765275SChristian Gromm 
most_match(struct device * dev,const struct device_driver * drv)494*d69d8048SGreg Kroah-Hartman static int most_match(struct device *dev, const struct device_driver *drv)
495b2765275SChristian Gromm {
496b2765275SChristian Gromm 	if (!strcmp(dev_name(dev), "most"))
497b2765275SChristian Gromm 		return 0;
498b2765275SChristian Gromm 	else
499b2765275SChristian Gromm 		return 1;
500b2765275SChristian Gromm }
501b2765275SChristian Gromm 
502408b18b1SRicardo B. Marliere static const struct bus_type mostbus = {
503b2765275SChristian Gromm 	.name = "most",
504b2765275SChristian Gromm 	.match = most_match,
505b2765275SChristian Gromm };
506b2765275SChristian Gromm 
links_show(struct device_driver * drv,char * buf)507b2765275SChristian Gromm static ssize_t links_show(struct device_driver *drv, char *buf)
508b2765275SChristian Gromm {
509b2765275SChristian Gromm 	struct show_links_data d = { .buf = buf };
510b2765275SChristian Gromm 
511b2765275SChristian Gromm 	bus_for_each_dev(&mostbus, NULL, &d, print_links);
512b2765275SChristian Gromm 	return d.offs;
513b2765275SChristian Gromm }
514b2765275SChristian Gromm 
components_show(struct device_driver * drv,char * buf)515b2765275SChristian Gromm static ssize_t components_show(struct device_driver *drv, char *buf)
516b2765275SChristian Gromm {
517b2765275SChristian Gromm 	struct most_component *comp;
518b2765275SChristian Gromm 	int offs = 0;
519b2765275SChristian Gromm 
520b2765275SChristian Gromm 	list_for_each_entry(comp, &comp_list, list) {
521b2765275SChristian Gromm 		offs += scnprintf(buf + offs, PAGE_SIZE - offs, "%s\n",
522b2765275SChristian Gromm 				 comp->name);
523b2765275SChristian Gromm 	}
524b2765275SChristian Gromm 	return offs;
525b2765275SChristian Gromm }
526b2765275SChristian Gromm 
527b2765275SChristian Gromm /**
528b2765275SChristian Gromm  * get_channel - get pointer to channel
529b2765275SChristian Gromm  * @mdev: name of the device interface
530b2765275SChristian Gromm  * @mdev_ch: name of channel
531b2765275SChristian Gromm  */
get_channel(char * mdev,char * mdev_ch)532b2765275SChristian Gromm static struct most_channel *get_channel(char *mdev, char *mdev_ch)
533b2765275SChristian Gromm {
534b2765275SChristian Gromm 	struct device *dev = NULL;
535b2765275SChristian Gromm 	struct most_interface *iface;
536b2765275SChristian Gromm 	struct most_channel *c, *tmp;
537b2765275SChristian Gromm 
538b2765275SChristian Gromm 	dev = bus_find_device_by_name(&mostbus, NULL, mdev);
539b2765275SChristian Gromm 	if (!dev)
540b2765275SChristian Gromm 		return NULL;
541b2765275SChristian Gromm 	put_device(dev);
542b2765275SChristian Gromm 	iface = dev_get_drvdata(dev);
543b2765275SChristian Gromm 	list_for_each_entry_safe(c, tmp, &iface->p->channel_list, list) {
544b2765275SChristian Gromm 		if (!strcmp(dev_name(&c->dev), mdev_ch))
545b2765275SChristian Gromm 			return c;
546b2765275SChristian Gromm 	}
547b2765275SChristian Gromm 	return NULL;
548b2765275SChristian Gromm }
549b2765275SChristian Gromm 
550b2765275SChristian Gromm static
link_channel_to_component(struct most_channel * c,struct most_component * comp,char * name,char * comp_param)551b2765275SChristian Gromm inline int link_channel_to_component(struct most_channel *c,
552b2765275SChristian Gromm 				     struct most_component *comp,
553b2765275SChristian Gromm 				     char *name,
554b2765275SChristian Gromm 				     char *comp_param)
555b2765275SChristian Gromm {
556b2765275SChristian Gromm 	int ret;
557b2765275SChristian Gromm 	struct most_component **comp_ptr;
558b2765275SChristian Gromm 
559b2765275SChristian Gromm 	if (!c->pipe0.comp)
560b2765275SChristian Gromm 		comp_ptr = &c->pipe0.comp;
561b2765275SChristian Gromm 	else if (!c->pipe1.comp)
562b2765275SChristian Gromm 		comp_ptr = &c->pipe1.comp;
563b2765275SChristian Gromm 	else
564b2765275SChristian Gromm 		return -ENOSPC;
565b2765275SChristian Gromm 
566b2765275SChristian Gromm 	*comp_ptr = comp;
567b2765275SChristian Gromm 	ret = comp->probe_channel(c->iface, c->channel_id, &c->cfg, name,
568b2765275SChristian Gromm 				  comp_param);
569b2765275SChristian Gromm 	if (ret) {
570b2765275SChristian Gromm 		*comp_ptr = NULL;
571b2765275SChristian Gromm 		return ret;
572b2765275SChristian Gromm 	}
573b2765275SChristian Gromm 	return 0;
574b2765275SChristian Gromm }
575b2765275SChristian Gromm 
most_set_cfg_buffer_size(char * mdev,char * mdev_ch,u16 val)576b2765275SChristian Gromm int most_set_cfg_buffer_size(char *mdev, char *mdev_ch, u16 val)
577b2765275SChristian Gromm {
578b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
579b2765275SChristian Gromm 
580b2765275SChristian Gromm 	if (!c)
581b2765275SChristian Gromm 		return -ENODEV;
582b2765275SChristian Gromm 	c->cfg.buffer_size = val;
583b2765275SChristian Gromm 	return 0;
584b2765275SChristian Gromm }
585b2765275SChristian Gromm 
most_set_cfg_subbuffer_size(char * mdev,char * mdev_ch,u16 val)586b2765275SChristian Gromm int most_set_cfg_subbuffer_size(char *mdev, char *mdev_ch, u16 val)
587b2765275SChristian Gromm {
588b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
589b2765275SChristian Gromm 
590b2765275SChristian Gromm 	if (!c)
591b2765275SChristian Gromm 		return -ENODEV;
592b2765275SChristian Gromm 	c->cfg.subbuffer_size = val;
593b2765275SChristian Gromm 	return 0;
594b2765275SChristian Gromm }
595b2765275SChristian Gromm 
most_set_cfg_dbr_size(char * mdev,char * mdev_ch,u16 val)596b2765275SChristian Gromm int most_set_cfg_dbr_size(char *mdev, char *mdev_ch, u16 val)
597b2765275SChristian Gromm {
598b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
599b2765275SChristian Gromm 
600b2765275SChristian Gromm 	if (!c)
601b2765275SChristian Gromm 		return -ENODEV;
602b2765275SChristian Gromm 	c->cfg.dbr_size = val;
603b2765275SChristian Gromm 	return 0;
604b2765275SChristian Gromm }
605b2765275SChristian Gromm 
most_set_cfg_num_buffers(char * mdev,char * mdev_ch,u16 val)606b2765275SChristian Gromm int most_set_cfg_num_buffers(char *mdev, char *mdev_ch, u16 val)
607b2765275SChristian Gromm {
608b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
609b2765275SChristian Gromm 
610b2765275SChristian Gromm 	if (!c)
611b2765275SChristian Gromm 		return -ENODEV;
612b2765275SChristian Gromm 	c->cfg.num_buffers = val;
613b2765275SChristian Gromm 	return 0;
614b2765275SChristian Gromm }
615b2765275SChristian Gromm 
most_set_cfg_datatype(char * mdev,char * mdev_ch,char * buf)616b2765275SChristian Gromm int most_set_cfg_datatype(char *mdev, char *mdev_ch, char *buf)
617b2765275SChristian Gromm {
618b2765275SChristian Gromm 	int i;
619b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
620b2765275SChristian Gromm 
621b2765275SChristian Gromm 	if (!c)
622b2765275SChristian Gromm 		return -ENODEV;
623b2765275SChristian Gromm 	for (i = 0; i < ARRAY_SIZE(ch_data_type); i++) {
624b2765275SChristian Gromm 		if (!strcmp(buf, ch_data_type[i].name)) {
625b2765275SChristian Gromm 			c->cfg.data_type = ch_data_type[i].most_ch_data_type;
626b2765275SChristian Gromm 			break;
627b2765275SChristian Gromm 		}
628b2765275SChristian Gromm 	}
629b2765275SChristian Gromm 
630b2765275SChristian Gromm 	if (i == ARRAY_SIZE(ch_data_type))
631b2765275SChristian Gromm 		dev_warn(&c->dev, "Invalid attribute settings\n");
632b2765275SChristian Gromm 	return 0;
633b2765275SChristian Gromm }
634b2765275SChristian Gromm 
most_set_cfg_direction(char * mdev,char * mdev_ch,char * buf)635b2765275SChristian Gromm int most_set_cfg_direction(char *mdev, char *mdev_ch, char *buf)
636b2765275SChristian Gromm {
637b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
638b2765275SChristian Gromm 
639b2765275SChristian Gromm 	if (!c)
640b2765275SChristian Gromm 		return -ENODEV;
641b2765275SChristian Gromm 	if (!strcmp(buf, "dir_rx")) {
642b2765275SChristian Gromm 		c->cfg.direction = MOST_CH_RX;
643b2765275SChristian Gromm 	} else if (!strcmp(buf, "rx")) {
644b2765275SChristian Gromm 		c->cfg.direction = MOST_CH_RX;
645b2765275SChristian Gromm 	} else if (!strcmp(buf, "dir_tx")) {
646b2765275SChristian Gromm 		c->cfg.direction = MOST_CH_TX;
647b2765275SChristian Gromm 	} else if (!strcmp(buf, "tx")) {
648b2765275SChristian Gromm 		c->cfg.direction = MOST_CH_TX;
649b2765275SChristian Gromm 	} else {
650b2765275SChristian Gromm 		dev_err(&c->dev, "Invalid direction\n");
651b2765275SChristian Gromm 		return -ENODATA;
652b2765275SChristian Gromm 	}
653b2765275SChristian Gromm 	return 0;
654b2765275SChristian Gromm }
655b2765275SChristian Gromm 
most_set_cfg_packets_xact(char * mdev,char * mdev_ch,u16 val)656b2765275SChristian Gromm int most_set_cfg_packets_xact(char *mdev, char *mdev_ch, u16 val)
657b2765275SChristian Gromm {
658b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
659b2765275SChristian Gromm 
660b2765275SChristian Gromm 	if (!c)
661b2765275SChristian Gromm 		return -ENODEV;
662b2765275SChristian Gromm 	c->cfg.packets_per_xact = val;
663b2765275SChristian Gromm 	return 0;
664b2765275SChristian Gromm }
665b2765275SChristian Gromm 
most_cfg_complete(char * comp_name)666b2765275SChristian Gromm int most_cfg_complete(char *comp_name)
667b2765275SChristian Gromm {
668b2765275SChristian Gromm 	struct most_component *comp;
669b2765275SChristian Gromm 
670b2765275SChristian Gromm 	comp = match_component(comp_name);
671b2765275SChristian Gromm 	if (!comp)
672b2765275SChristian Gromm 		return -ENODEV;
673b2765275SChristian Gromm 
674b2765275SChristian Gromm 	return comp->cfg_complete();
675b2765275SChristian Gromm }
676b2765275SChristian Gromm 
most_add_link(char * mdev,char * mdev_ch,char * comp_name,char * link_name,char * comp_param)677b2765275SChristian Gromm int most_add_link(char *mdev, char *mdev_ch, char *comp_name, char *link_name,
678b2765275SChristian Gromm 		  char *comp_param)
679b2765275SChristian Gromm {
680b2765275SChristian Gromm 	struct most_channel *c = get_channel(mdev, mdev_ch);
681b2765275SChristian Gromm 	struct most_component *comp = match_component(comp_name);
682b2765275SChristian Gromm 
683b2765275SChristian Gromm 	if (!c || !comp)
684b2765275SChristian Gromm 		return -ENODEV;
685b2765275SChristian Gromm 
686b2765275SChristian Gromm 	return link_channel_to_component(c, comp, link_name, comp_param);
687b2765275SChristian Gromm }
688b2765275SChristian Gromm 
most_remove_link(char * mdev,char * mdev_ch,char * comp_name)689b2765275SChristian Gromm int most_remove_link(char *mdev, char *mdev_ch, char *comp_name)
690b2765275SChristian Gromm {
691b2765275SChristian Gromm 	struct most_channel *c;
692b2765275SChristian Gromm 	struct most_component *comp;
693b2765275SChristian Gromm 
694b2765275SChristian Gromm 	comp = match_component(comp_name);
695b2765275SChristian Gromm 	if (!comp)
696b2765275SChristian Gromm 		return -ENODEV;
697b2765275SChristian Gromm 	c = get_channel(mdev, mdev_ch);
698b2765275SChristian Gromm 	if (!c)
699b2765275SChristian Gromm 		return -ENODEV;
700b2765275SChristian Gromm 
701b2765275SChristian Gromm 	if (comp->disconnect_channel(c->iface, c->channel_id))
702b2765275SChristian Gromm 		return -EIO;
703b2765275SChristian Gromm 	if (c->pipe0.comp == comp)
704b2765275SChristian Gromm 		c->pipe0.comp = NULL;
705b2765275SChristian Gromm 	if (c->pipe1.comp == comp)
706b2765275SChristian Gromm 		c->pipe1.comp = NULL;
707b2765275SChristian Gromm 	return 0;
708b2765275SChristian Gromm }
709b2765275SChristian Gromm 
710b2765275SChristian Gromm #define DRV_ATTR(_name)  (&driver_attr_##_name.attr)
711b2765275SChristian Gromm 
712b2765275SChristian Gromm static DRIVER_ATTR_RO(links);
713b2765275SChristian Gromm static DRIVER_ATTR_RO(components);
714b2765275SChristian Gromm 
715b2765275SChristian Gromm static struct attribute *mc_attrs[] = {
716b2765275SChristian Gromm 	DRV_ATTR(links),
717b2765275SChristian Gromm 	DRV_ATTR(components),
718b2765275SChristian Gromm 	NULL,
719b2765275SChristian Gromm };
720b2765275SChristian Gromm 
72126c2e922SRikard Falkeborn static const struct attribute_group mc_attr_group = {
722b2765275SChristian Gromm 	.attrs = mc_attrs,
723b2765275SChristian Gromm };
724b2765275SChristian Gromm 
725b2765275SChristian Gromm static const struct attribute_group *mc_attr_groups[] = {
726b2765275SChristian Gromm 	&mc_attr_group,
727b2765275SChristian Gromm 	NULL,
728b2765275SChristian Gromm };
729b2765275SChristian Gromm 
730b2765275SChristian Gromm static struct device_driver mostbus_driver = {
731b2765275SChristian Gromm 	.name = "most_core",
732b2765275SChristian Gromm 	.bus = &mostbus,
733b2765275SChristian Gromm 	.groups = mc_attr_groups,
734b2765275SChristian Gromm };
735b2765275SChristian Gromm 
trash_mbo(struct mbo * mbo)736b2765275SChristian Gromm static inline void trash_mbo(struct mbo *mbo)
737b2765275SChristian Gromm {
738b2765275SChristian Gromm 	unsigned long flags;
739b2765275SChristian Gromm 	struct most_channel *c = mbo->context;
740b2765275SChristian Gromm 
741b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
742b2765275SChristian Gromm 	list_add(&mbo->list, &c->trash_fifo);
743b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
744b2765275SChristian Gromm }
745b2765275SChristian Gromm 
hdm_mbo_ready(struct most_channel * c)746b2765275SChristian Gromm static bool hdm_mbo_ready(struct most_channel *c)
747b2765275SChristian Gromm {
748b2765275SChristian Gromm 	bool empty;
749b2765275SChristian Gromm 
750b2765275SChristian Gromm 	if (c->enqueue_halt)
751b2765275SChristian Gromm 		return false;
752b2765275SChristian Gromm 
753b2765275SChristian Gromm 	spin_lock_irq(&c->fifo_lock);
754b2765275SChristian Gromm 	empty = list_empty(&c->halt_fifo);
755b2765275SChristian Gromm 	spin_unlock_irq(&c->fifo_lock);
756b2765275SChristian Gromm 
757b2765275SChristian Gromm 	return !empty;
758b2765275SChristian Gromm }
759b2765275SChristian Gromm 
nq_hdm_mbo(struct mbo * mbo)760b2765275SChristian Gromm static void nq_hdm_mbo(struct mbo *mbo)
761b2765275SChristian Gromm {
762b2765275SChristian Gromm 	unsigned long flags;
763b2765275SChristian Gromm 	struct most_channel *c = mbo->context;
764b2765275SChristian Gromm 
765b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
766b2765275SChristian Gromm 	list_add_tail(&mbo->list, &c->halt_fifo);
767b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
768b2765275SChristian Gromm 	wake_up_interruptible(&c->hdm_fifo_wq);
769b2765275SChristian Gromm }
770b2765275SChristian Gromm 
hdm_enqueue_thread(void * data)771b2765275SChristian Gromm static int hdm_enqueue_thread(void *data)
772b2765275SChristian Gromm {
773b2765275SChristian Gromm 	struct most_channel *c = data;
774b2765275SChristian Gromm 	struct mbo *mbo;
775b2765275SChristian Gromm 	int ret;
776b2765275SChristian Gromm 	typeof(c->iface->enqueue) enqueue = c->iface->enqueue;
777b2765275SChristian Gromm 
778b2765275SChristian Gromm 	while (likely(!kthread_should_stop())) {
779b2765275SChristian Gromm 		wait_event_interruptible(c->hdm_fifo_wq,
780b2765275SChristian Gromm 					 hdm_mbo_ready(c) ||
781b2765275SChristian Gromm 					 kthread_should_stop());
782b2765275SChristian Gromm 
783b2765275SChristian Gromm 		mutex_lock(&c->nq_mutex);
784b2765275SChristian Gromm 		spin_lock_irq(&c->fifo_lock);
785b2765275SChristian Gromm 		if (unlikely(c->enqueue_halt || list_empty(&c->halt_fifo))) {
786b2765275SChristian Gromm 			spin_unlock_irq(&c->fifo_lock);
787b2765275SChristian Gromm 			mutex_unlock(&c->nq_mutex);
788b2765275SChristian Gromm 			continue;
789b2765275SChristian Gromm 		}
790b2765275SChristian Gromm 
791b2765275SChristian Gromm 		mbo = list_pop_mbo(&c->halt_fifo);
792b2765275SChristian Gromm 		spin_unlock_irq(&c->fifo_lock);
793b2765275SChristian Gromm 
794b2765275SChristian Gromm 		if (c->cfg.direction == MOST_CH_RX)
795b2765275SChristian Gromm 			mbo->buffer_length = c->cfg.buffer_size;
796b2765275SChristian Gromm 
797b2765275SChristian Gromm 		ret = enqueue(mbo->ifp, mbo->hdm_channel_id, mbo);
798b2765275SChristian Gromm 		mutex_unlock(&c->nq_mutex);
799b2765275SChristian Gromm 
800b2765275SChristian Gromm 		if (unlikely(ret)) {
801b2765275SChristian Gromm 			dev_err(&c->dev, "Buffer enqueue failed\n");
802b2765275SChristian Gromm 			nq_hdm_mbo(mbo);
803b2765275SChristian Gromm 			c->hdm_enqueue_task = NULL;
804b2765275SChristian Gromm 			return 0;
805b2765275SChristian Gromm 		}
806b2765275SChristian Gromm 	}
807b2765275SChristian Gromm 
808b2765275SChristian Gromm 	return 0;
809b2765275SChristian Gromm }
810b2765275SChristian Gromm 
run_enqueue_thread(struct most_channel * c,int channel_id)811b2765275SChristian Gromm static int run_enqueue_thread(struct most_channel *c, int channel_id)
812b2765275SChristian Gromm {
813b2765275SChristian Gromm 	struct task_struct *task =
814b2765275SChristian Gromm 		kthread_run(hdm_enqueue_thread, c, "hdm_fifo_%d",
815b2765275SChristian Gromm 			    channel_id);
816b2765275SChristian Gromm 
817b2765275SChristian Gromm 	if (IS_ERR(task))
818b2765275SChristian Gromm 		return PTR_ERR(task);
819b2765275SChristian Gromm 
820b2765275SChristian Gromm 	c->hdm_enqueue_task = task;
821b2765275SChristian Gromm 	return 0;
822b2765275SChristian Gromm }
823b2765275SChristian Gromm 
824b2765275SChristian Gromm /**
825b2765275SChristian Gromm  * arm_mbo - recycle MBO for further usage
826b2765275SChristian Gromm  * @mbo: most buffer
827b2765275SChristian Gromm  *
828b2765275SChristian Gromm  * This puts an MBO back to the list to have it ready for up coming
829b2765275SChristian Gromm  * tx transactions.
830b2765275SChristian Gromm  *
831b2765275SChristian Gromm  * In case the MBO belongs to a channel that recently has been
832b2765275SChristian Gromm  * poisoned, the MBO is scheduled to be trashed.
833b2765275SChristian Gromm  * Calls the completion handler of an attached component.
834b2765275SChristian Gromm  */
arm_mbo(struct mbo * mbo)835b2765275SChristian Gromm static void arm_mbo(struct mbo *mbo)
836b2765275SChristian Gromm {
837b2765275SChristian Gromm 	unsigned long flags;
838b2765275SChristian Gromm 	struct most_channel *c;
839b2765275SChristian Gromm 
840b2765275SChristian Gromm 	c = mbo->context;
841b2765275SChristian Gromm 
842b2765275SChristian Gromm 	if (c->is_poisoned) {
843b2765275SChristian Gromm 		trash_mbo(mbo);
844b2765275SChristian Gromm 		return;
845b2765275SChristian Gromm 	}
846b2765275SChristian Gromm 
847b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
848b2765275SChristian Gromm 	++*mbo->num_buffers_ptr;
849b2765275SChristian Gromm 	list_add_tail(&mbo->list, &c->fifo);
850b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
851b2765275SChristian Gromm 
852b2765275SChristian Gromm 	if (c->pipe0.refs && c->pipe0.comp->tx_completion)
853b2765275SChristian Gromm 		c->pipe0.comp->tx_completion(c->iface, c->channel_id);
854b2765275SChristian Gromm 
855b2765275SChristian Gromm 	if (c->pipe1.refs && c->pipe1.comp->tx_completion)
856b2765275SChristian Gromm 		c->pipe1.comp->tx_completion(c->iface, c->channel_id);
857b2765275SChristian Gromm }
858b2765275SChristian Gromm 
859b2765275SChristian Gromm /**
860b2765275SChristian Gromm  * arm_mbo_chain - helper function that arms an MBO chain for the HDM
861b2765275SChristian Gromm  * @c: pointer to interface channel
862b2765275SChristian Gromm  * @dir: direction of the channel
863b2765275SChristian Gromm  * @compl: pointer to completion function
864b2765275SChristian Gromm  *
865b2765275SChristian Gromm  * This allocates buffer objects including the containing DMA coherent
866b2765275SChristian Gromm  * buffer and puts them in the fifo.
867b2765275SChristian Gromm  * Buffers of Rx channels are put in the kthread fifo, hence immediately
868b2765275SChristian Gromm  * submitted to the HDM.
869b2765275SChristian Gromm  *
870b2765275SChristian Gromm  * Returns the number of allocated and enqueued MBOs.
871b2765275SChristian Gromm  */
arm_mbo_chain(struct most_channel * c,int dir,void (* compl)(struct mbo *))872b2765275SChristian Gromm static int arm_mbo_chain(struct most_channel *c, int dir,
873b2765275SChristian Gromm 			 void (*compl)(struct mbo *))
874b2765275SChristian Gromm {
875b2765275SChristian Gromm 	unsigned int i;
876b2765275SChristian Gromm 	struct mbo *mbo;
877b2765275SChristian Gromm 	unsigned long flags;
878b2765275SChristian Gromm 	u32 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len;
879b2765275SChristian Gromm 
880b2765275SChristian Gromm 	atomic_set(&c->mbo_nq_level, 0);
881b2765275SChristian Gromm 
882b2765275SChristian Gromm 	for (i = 0; i < c->cfg.num_buffers; i++) {
883b2765275SChristian Gromm 		mbo = kzalloc(sizeof(*mbo), GFP_KERNEL);
884b2765275SChristian Gromm 		if (!mbo)
885b2765275SChristian Gromm 			goto flush_fifos;
886b2765275SChristian Gromm 
887b2765275SChristian Gromm 		mbo->context = c;
888b2765275SChristian Gromm 		mbo->ifp = c->iface;
889b2765275SChristian Gromm 		mbo->hdm_channel_id = c->channel_id;
890b2765275SChristian Gromm 		if (c->iface->dma_alloc) {
891b2765275SChristian Gromm 			mbo->virt_address =
892b2765275SChristian Gromm 				c->iface->dma_alloc(mbo, coherent_buf_size);
893b2765275SChristian Gromm 		} else {
894b2765275SChristian Gromm 			mbo->virt_address =
895b2765275SChristian Gromm 				kzalloc(coherent_buf_size, GFP_KERNEL);
896b2765275SChristian Gromm 		}
897b2765275SChristian Gromm 		if (!mbo->virt_address)
898b2765275SChristian Gromm 			goto release_mbo;
899b2765275SChristian Gromm 
900b2765275SChristian Gromm 		mbo->complete = compl;
901b2765275SChristian Gromm 		mbo->num_buffers_ptr = &dummy_num_buffers;
902b2765275SChristian Gromm 		if (dir == MOST_CH_RX) {
903b2765275SChristian Gromm 			nq_hdm_mbo(mbo);
904b2765275SChristian Gromm 			atomic_inc(&c->mbo_nq_level);
905b2765275SChristian Gromm 		} else {
906b2765275SChristian Gromm 			spin_lock_irqsave(&c->fifo_lock, flags);
907b2765275SChristian Gromm 			list_add_tail(&mbo->list, &c->fifo);
908b2765275SChristian Gromm 			spin_unlock_irqrestore(&c->fifo_lock, flags);
909b2765275SChristian Gromm 		}
910b2765275SChristian Gromm 	}
911b2765275SChristian Gromm 	return c->cfg.num_buffers;
912b2765275SChristian Gromm 
913b2765275SChristian Gromm release_mbo:
914b2765275SChristian Gromm 	kfree(mbo);
915b2765275SChristian Gromm 
916b2765275SChristian Gromm flush_fifos:
917b2765275SChristian Gromm 	flush_channel_fifos(c);
918b2765275SChristian Gromm 	return 0;
919b2765275SChristian Gromm }
920b2765275SChristian Gromm 
921b2765275SChristian Gromm /**
922b2765275SChristian Gromm  * most_submit_mbo - submits an MBO to fifo
923b2765275SChristian Gromm  * @mbo: most buffer
924b2765275SChristian Gromm  */
most_submit_mbo(struct mbo * mbo)925b2765275SChristian Gromm void most_submit_mbo(struct mbo *mbo)
926b2765275SChristian Gromm {
927b2765275SChristian Gromm 	if (WARN_ONCE(!mbo || !mbo->context,
928b2765275SChristian Gromm 		      "Bad buffer or missing channel reference\n"))
929b2765275SChristian Gromm 		return;
930b2765275SChristian Gromm 
931b2765275SChristian Gromm 	nq_hdm_mbo(mbo);
932b2765275SChristian Gromm }
933b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_submit_mbo);
934b2765275SChristian Gromm 
935b2765275SChristian Gromm /**
936b2765275SChristian Gromm  * most_write_completion - write completion handler
937b2765275SChristian Gromm  * @mbo: most buffer
938b2765275SChristian Gromm  *
939b2765275SChristian Gromm  * This recycles the MBO for further usage. In case the channel has been
940b2765275SChristian Gromm  * poisoned, the MBO is scheduled to be trashed.
941b2765275SChristian Gromm  */
most_write_completion(struct mbo * mbo)942b2765275SChristian Gromm static void most_write_completion(struct mbo *mbo)
943b2765275SChristian Gromm {
944b2765275SChristian Gromm 	struct most_channel *c;
945b2765275SChristian Gromm 
946b2765275SChristian Gromm 	c = mbo->context;
947b2765275SChristian Gromm 	if (unlikely(c->is_poisoned || (mbo->status == MBO_E_CLOSE)))
948b2765275SChristian Gromm 		trash_mbo(mbo);
949b2765275SChristian Gromm 	else
950b2765275SChristian Gromm 		arm_mbo(mbo);
951b2765275SChristian Gromm }
952b2765275SChristian Gromm 
channel_has_mbo(struct most_interface * iface,int id,struct most_component * comp)953b2765275SChristian Gromm int channel_has_mbo(struct most_interface *iface, int id,
954b2765275SChristian Gromm 		    struct most_component *comp)
955b2765275SChristian Gromm {
956b2765275SChristian Gromm 	struct most_channel *c = iface->p->channel[id];
957b2765275SChristian Gromm 	unsigned long flags;
958b2765275SChristian Gromm 	int empty;
959b2765275SChristian Gromm 
960b2765275SChristian Gromm 	if (unlikely(!c))
961b2765275SChristian Gromm 		return -EINVAL;
962b2765275SChristian Gromm 
963b2765275SChristian Gromm 	if (c->pipe0.refs && c->pipe1.refs &&
964b2765275SChristian Gromm 	    ((comp == c->pipe0.comp && c->pipe0.num_buffers <= 0) ||
965b2765275SChristian Gromm 	     (comp == c->pipe1.comp && c->pipe1.num_buffers <= 0)))
966b2765275SChristian Gromm 		return 0;
967b2765275SChristian Gromm 
968b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
969b2765275SChristian Gromm 	empty = list_empty(&c->fifo);
970b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
971b2765275SChristian Gromm 	return !empty;
972b2765275SChristian Gromm }
973b2765275SChristian Gromm EXPORT_SYMBOL_GPL(channel_has_mbo);
974b2765275SChristian Gromm 
975b2765275SChristian Gromm /**
976b2765275SChristian Gromm  * most_get_mbo - get pointer to an MBO of pool
977b2765275SChristian Gromm  * @iface: pointer to interface instance
978b2765275SChristian Gromm  * @id: channel ID
979b2765275SChristian Gromm  * @comp: driver component
980b2765275SChristian Gromm  *
981b2765275SChristian Gromm  * This attempts to get a free buffer out of the channel fifo.
982b2765275SChristian Gromm  * Returns a pointer to MBO on success or NULL otherwise.
983b2765275SChristian Gromm  */
most_get_mbo(struct most_interface * iface,int id,struct most_component * comp)984b2765275SChristian Gromm struct mbo *most_get_mbo(struct most_interface *iface, int id,
985b2765275SChristian Gromm 			 struct most_component *comp)
986b2765275SChristian Gromm {
987b2765275SChristian Gromm 	struct mbo *mbo;
988b2765275SChristian Gromm 	struct most_channel *c;
989b2765275SChristian Gromm 	unsigned long flags;
990b2765275SChristian Gromm 	int *num_buffers_ptr;
991b2765275SChristian Gromm 
992b2765275SChristian Gromm 	c = iface->p->channel[id];
993b2765275SChristian Gromm 	if (unlikely(!c))
994b2765275SChristian Gromm 		return NULL;
995b2765275SChristian Gromm 
996b2765275SChristian Gromm 	if (c->pipe0.refs && c->pipe1.refs &&
997b2765275SChristian Gromm 	    ((comp == c->pipe0.comp && c->pipe0.num_buffers <= 0) ||
998b2765275SChristian Gromm 	     (comp == c->pipe1.comp && c->pipe1.num_buffers <= 0)))
999b2765275SChristian Gromm 		return NULL;
1000b2765275SChristian Gromm 
1001b2765275SChristian Gromm 	if (comp == c->pipe0.comp)
1002b2765275SChristian Gromm 		num_buffers_ptr = &c->pipe0.num_buffers;
1003b2765275SChristian Gromm 	else if (comp == c->pipe1.comp)
1004b2765275SChristian Gromm 		num_buffers_ptr = &c->pipe1.num_buffers;
1005b2765275SChristian Gromm 	else
1006b2765275SChristian Gromm 		num_buffers_ptr = &dummy_num_buffers;
1007b2765275SChristian Gromm 
1008b2765275SChristian Gromm 	spin_lock_irqsave(&c->fifo_lock, flags);
1009b2765275SChristian Gromm 	if (list_empty(&c->fifo)) {
1010b2765275SChristian Gromm 		spin_unlock_irqrestore(&c->fifo_lock, flags);
1011b2765275SChristian Gromm 		return NULL;
1012b2765275SChristian Gromm 	}
1013b2765275SChristian Gromm 	mbo = list_pop_mbo(&c->fifo);
1014b2765275SChristian Gromm 	--*num_buffers_ptr;
1015b2765275SChristian Gromm 	spin_unlock_irqrestore(&c->fifo_lock, flags);
1016b2765275SChristian Gromm 
1017b2765275SChristian Gromm 	mbo->num_buffers_ptr = num_buffers_ptr;
1018b2765275SChristian Gromm 	mbo->buffer_length = c->cfg.buffer_size;
1019b2765275SChristian Gromm 	return mbo;
1020b2765275SChristian Gromm }
1021b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_get_mbo);
1022b2765275SChristian Gromm 
1023b2765275SChristian Gromm /**
1024b2765275SChristian Gromm  * most_put_mbo - return buffer to pool
1025b2765275SChristian Gromm  * @mbo: most buffer
1026b2765275SChristian Gromm  */
most_put_mbo(struct mbo * mbo)1027b2765275SChristian Gromm void most_put_mbo(struct mbo *mbo)
1028b2765275SChristian Gromm {
1029b2765275SChristian Gromm 	struct most_channel *c = mbo->context;
1030b2765275SChristian Gromm 
1031b2765275SChristian Gromm 	if (c->cfg.direction == MOST_CH_TX) {
1032b2765275SChristian Gromm 		arm_mbo(mbo);
1033b2765275SChristian Gromm 		return;
1034b2765275SChristian Gromm 	}
1035b2765275SChristian Gromm 	nq_hdm_mbo(mbo);
1036b2765275SChristian Gromm 	atomic_inc(&c->mbo_nq_level);
1037b2765275SChristian Gromm }
1038b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_put_mbo);
1039b2765275SChristian Gromm 
1040b2765275SChristian Gromm /**
1041b2765275SChristian Gromm  * most_read_completion - read completion handler
1042b2765275SChristian Gromm  * @mbo: most buffer
1043b2765275SChristian Gromm  *
1044b2765275SChristian Gromm  * This function is called by the HDM when data has been received from the
1045b2765275SChristian Gromm  * hardware and copied to the buffer of the MBO.
1046b2765275SChristian Gromm  *
1047b2765275SChristian Gromm  * In case the channel has been poisoned it puts the buffer in the trash queue.
1048b2765275SChristian Gromm  * Otherwise, it passes the buffer to an component for further processing.
1049b2765275SChristian Gromm  */
most_read_completion(struct mbo * mbo)1050b2765275SChristian Gromm static void most_read_completion(struct mbo *mbo)
1051b2765275SChristian Gromm {
1052b2765275SChristian Gromm 	struct most_channel *c = mbo->context;
1053b2765275SChristian Gromm 
1054b2765275SChristian Gromm 	if (unlikely(c->is_poisoned || (mbo->status == MBO_E_CLOSE))) {
1055b2765275SChristian Gromm 		trash_mbo(mbo);
1056b2765275SChristian Gromm 		return;
1057b2765275SChristian Gromm 	}
1058b2765275SChristian Gromm 
1059b2765275SChristian Gromm 	if (mbo->status == MBO_E_INVAL) {
1060b2765275SChristian Gromm 		nq_hdm_mbo(mbo);
1061b2765275SChristian Gromm 		atomic_inc(&c->mbo_nq_level);
1062b2765275SChristian Gromm 		return;
1063b2765275SChristian Gromm 	}
1064b2765275SChristian Gromm 
1065b2765275SChristian Gromm 	if (atomic_sub_and_test(1, &c->mbo_nq_level))
1066b2765275SChristian Gromm 		c->is_starving = 1;
1067b2765275SChristian Gromm 
1068b2765275SChristian Gromm 	if (c->pipe0.refs && c->pipe0.comp->rx_completion &&
1069b2765275SChristian Gromm 	    c->pipe0.comp->rx_completion(mbo) == 0)
1070b2765275SChristian Gromm 		return;
1071b2765275SChristian Gromm 
1072b2765275SChristian Gromm 	if (c->pipe1.refs && c->pipe1.comp->rx_completion &&
1073b2765275SChristian Gromm 	    c->pipe1.comp->rx_completion(mbo) == 0)
1074b2765275SChristian Gromm 		return;
1075b2765275SChristian Gromm 
1076b2765275SChristian Gromm 	most_put_mbo(mbo);
1077b2765275SChristian Gromm }
1078b2765275SChristian Gromm 
1079b2765275SChristian Gromm /**
1080b2765275SChristian Gromm  * most_start_channel - prepares a channel for communication
1081b2765275SChristian Gromm  * @iface: pointer to interface instance
1082b2765275SChristian Gromm  * @id: channel ID
1083b2765275SChristian Gromm  * @comp: driver component
1084b2765275SChristian Gromm  *
1085b2765275SChristian Gromm  * This prepares the channel for usage. Cross-checks whether the
1086b2765275SChristian Gromm  * channel's been properly configured.
1087b2765275SChristian Gromm  *
1088b2765275SChristian Gromm  * Returns 0 on success or error code otherwise.
1089b2765275SChristian Gromm  */
most_start_channel(struct most_interface * iface,int id,struct most_component * comp)1090b2765275SChristian Gromm int most_start_channel(struct most_interface *iface, int id,
1091b2765275SChristian Gromm 		       struct most_component *comp)
1092b2765275SChristian Gromm {
1093b2765275SChristian Gromm 	int num_buffer;
1094b2765275SChristian Gromm 	int ret;
1095b2765275SChristian Gromm 	struct most_channel *c = iface->p->channel[id];
1096b2765275SChristian Gromm 
1097b2765275SChristian Gromm 	if (unlikely(!c))
1098b2765275SChristian Gromm 		return -EINVAL;
1099b2765275SChristian Gromm 
1100b2765275SChristian Gromm 	mutex_lock(&c->start_mutex);
1101b2765275SChristian Gromm 	if (c->pipe0.refs + c->pipe1.refs > 0)
1102b2765275SChristian Gromm 		goto out; /* already started by another component */
1103b2765275SChristian Gromm 
1104b2765275SChristian Gromm 	if (!try_module_get(iface->mod)) {
1105b2765275SChristian Gromm 		dev_err(&c->dev, "Failed to acquire HDM lock\n");
1106b2765275SChristian Gromm 		mutex_unlock(&c->start_mutex);
1107b2765275SChristian Gromm 		return -ENOLCK;
1108b2765275SChristian Gromm 	}
1109b2765275SChristian Gromm 
1110b2765275SChristian Gromm 	c->cfg.extra_len = 0;
1111b2765275SChristian Gromm 	if (c->iface->configure(c->iface, c->channel_id, &c->cfg)) {
1112b2765275SChristian Gromm 		dev_err(&c->dev, "Channel configuration failed. Go check settings...\n");
1113b2765275SChristian Gromm 		ret = -EINVAL;
1114b2765275SChristian Gromm 		goto err_put_module;
1115b2765275SChristian Gromm 	}
1116b2765275SChristian Gromm 
1117b2765275SChristian Gromm 	init_waitqueue_head(&c->hdm_fifo_wq);
1118b2765275SChristian Gromm 
1119b2765275SChristian Gromm 	if (c->cfg.direction == MOST_CH_RX)
1120b2765275SChristian Gromm 		num_buffer = arm_mbo_chain(c, c->cfg.direction,
1121b2765275SChristian Gromm 					   most_read_completion);
1122b2765275SChristian Gromm 	else
1123b2765275SChristian Gromm 		num_buffer = arm_mbo_chain(c, c->cfg.direction,
1124b2765275SChristian Gromm 					   most_write_completion);
1125b2765275SChristian Gromm 	if (unlikely(!num_buffer)) {
1126b2765275SChristian Gromm 		ret = -ENOMEM;
1127b2765275SChristian Gromm 		goto err_put_module;
1128b2765275SChristian Gromm 	}
1129b2765275SChristian Gromm 
1130b2765275SChristian Gromm 	ret = run_enqueue_thread(c, id);
1131b2765275SChristian Gromm 	if (ret)
1132b2765275SChristian Gromm 		goto err_put_module;
1133b2765275SChristian Gromm 
1134b2765275SChristian Gromm 	c->is_starving = 0;
1135b2765275SChristian Gromm 	c->pipe0.num_buffers = c->cfg.num_buffers / 2;
1136b2765275SChristian Gromm 	c->pipe1.num_buffers = c->cfg.num_buffers - c->pipe0.num_buffers;
1137b2765275SChristian Gromm 	atomic_set(&c->mbo_ref, num_buffer);
1138b2765275SChristian Gromm 
1139b2765275SChristian Gromm out:
1140b2765275SChristian Gromm 	if (comp == c->pipe0.comp)
1141b2765275SChristian Gromm 		c->pipe0.refs++;
1142b2765275SChristian Gromm 	if (comp == c->pipe1.comp)
1143b2765275SChristian Gromm 		c->pipe1.refs++;
1144b2765275SChristian Gromm 	mutex_unlock(&c->start_mutex);
1145b2765275SChristian Gromm 	return 0;
1146b2765275SChristian Gromm 
1147b2765275SChristian Gromm err_put_module:
1148b2765275SChristian Gromm 	module_put(iface->mod);
1149b2765275SChristian Gromm 	mutex_unlock(&c->start_mutex);
1150b2765275SChristian Gromm 	return ret;
1151b2765275SChristian Gromm }
1152b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_start_channel);
1153b2765275SChristian Gromm 
1154b2765275SChristian Gromm /**
1155b2765275SChristian Gromm  * most_stop_channel - stops a running channel
1156b2765275SChristian Gromm  * @iface: pointer to interface instance
1157b2765275SChristian Gromm  * @id: channel ID
1158b2765275SChristian Gromm  * @comp: driver component
1159b2765275SChristian Gromm  */
most_stop_channel(struct most_interface * iface,int id,struct most_component * comp)1160b2765275SChristian Gromm int most_stop_channel(struct most_interface *iface, int id,
1161b2765275SChristian Gromm 		      struct most_component *comp)
1162b2765275SChristian Gromm {
1163b2765275SChristian Gromm 	struct most_channel *c;
1164b2765275SChristian Gromm 
1165b2765275SChristian Gromm 	if (unlikely((!iface) || (id >= iface->num_channels) || (id < 0))) {
1166b2765275SChristian Gromm 		pr_err("Bad interface or index out of range\n");
1167b2765275SChristian Gromm 		return -EINVAL;
1168b2765275SChristian Gromm 	}
1169b2765275SChristian Gromm 	c = iface->p->channel[id];
1170b2765275SChristian Gromm 	if (unlikely(!c))
1171b2765275SChristian Gromm 		return -EINVAL;
1172b2765275SChristian Gromm 
1173b2765275SChristian Gromm 	mutex_lock(&c->start_mutex);
1174b2765275SChristian Gromm 	if (c->pipe0.refs + c->pipe1.refs >= 2)
1175b2765275SChristian Gromm 		goto out;
1176b2765275SChristian Gromm 
1177b2765275SChristian Gromm 	if (c->hdm_enqueue_task)
1178b2765275SChristian Gromm 		kthread_stop(c->hdm_enqueue_task);
1179b2765275SChristian Gromm 	c->hdm_enqueue_task = NULL;
1180b2765275SChristian Gromm 
1181b2765275SChristian Gromm 	if (iface->mod)
1182b2765275SChristian Gromm 		module_put(iface->mod);
1183b2765275SChristian Gromm 
1184b2765275SChristian Gromm 	c->is_poisoned = true;
1185b2765275SChristian Gromm 	if (c->iface->poison_channel(c->iface, c->channel_id)) {
1186b2765275SChristian Gromm 		dev_err(&c->dev, "Failed to stop channel %d of interface %s\n", c->channel_id,
1187b2765275SChristian Gromm 			c->iface->description);
1188b2765275SChristian Gromm 		mutex_unlock(&c->start_mutex);
1189b2765275SChristian Gromm 		return -EAGAIN;
1190b2765275SChristian Gromm 	}
1191b2765275SChristian Gromm 	flush_trash_fifo(c);
1192b2765275SChristian Gromm 	flush_channel_fifos(c);
1193b2765275SChristian Gromm 
1194b2765275SChristian Gromm #ifdef CMPL_INTERRUPTIBLE
1195b2765275SChristian Gromm 	if (wait_for_completion_interruptible(&c->cleanup)) {
1196b2765275SChristian Gromm 		dev_err(&c->dev, "Interrupted while cleaning up channel %d\n", c->channel_id);
1197b2765275SChristian Gromm 		mutex_unlock(&c->start_mutex);
1198b2765275SChristian Gromm 		return -EINTR;
1199b2765275SChristian Gromm 	}
1200b2765275SChristian Gromm #else
1201b2765275SChristian Gromm 	wait_for_completion(&c->cleanup);
1202b2765275SChristian Gromm #endif
1203b2765275SChristian Gromm 	c->is_poisoned = false;
1204b2765275SChristian Gromm 
1205b2765275SChristian Gromm out:
1206b2765275SChristian Gromm 	if (comp == c->pipe0.comp)
1207b2765275SChristian Gromm 		c->pipe0.refs--;
1208b2765275SChristian Gromm 	if (comp == c->pipe1.comp)
1209b2765275SChristian Gromm 		c->pipe1.refs--;
1210b2765275SChristian Gromm 	mutex_unlock(&c->start_mutex);
1211b2765275SChristian Gromm 	return 0;
1212b2765275SChristian Gromm }
1213b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_stop_channel);
1214b2765275SChristian Gromm 
1215b2765275SChristian Gromm /**
1216b2765275SChristian Gromm  * most_register_component - registers a driver component with the core
1217b2765275SChristian Gromm  * @comp: driver component
1218b2765275SChristian Gromm  */
most_register_component(struct most_component * comp)1219b2765275SChristian Gromm int most_register_component(struct most_component *comp)
1220b2765275SChristian Gromm {
1221b2765275SChristian Gromm 	if (!comp) {
1222b2765275SChristian Gromm 		pr_err("Bad component\n");
1223b2765275SChristian Gromm 		return -EINVAL;
1224b2765275SChristian Gromm 	}
1225b2765275SChristian Gromm 	list_add_tail(&comp->list, &comp_list);
1226b2765275SChristian Gromm 	return 0;
1227b2765275SChristian Gromm }
1228b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_register_component);
1229b2765275SChristian Gromm 
disconnect_channels(struct device * dev,void * data)1230b2765275SChristian Gromm static int disconnect_channels(struct device *dev, void *data)
1231b2765275SChristian Gromm {
1232b2765275SChristian Gromm 	struct most_interface *iface;
1233b2765275SChristian Gromm 	struct most_channel *c, *tmp;
1234b2765275SChristian Gromm 	struct most_component *comp = data;
1235b2765275SChristian Gromm 
1236b2765275SChristian Gromm 	iface = dev_get_drvdata(dev);
1237b2765275SChristian Gromm 	list_for_each_entry_safe(c, tmp, &iface->p->channel_list, list) {
1238b2765275SChristian Gromm 		if (c->pipe0.comp == comp || c->pipe1.comp == comp)
1239b2765275SChristian Gromm 			comp->disconnect_channel(c->iface, c->channel_id);
1240b2765275SChristian Gromm 		if (c->pipe0.comp == comp)
1241b2765275SChristian Gromm 			c->pipe0.comp = NULL;
1242b2765275SChristian Gromm 		if (c->pipe1.comp == comp)
1243b2765275SChristian Gromm 			c->pipe1.comp = NULL;
1244b2765275SChristian Gromm 	}
1245b2765275SChristian Gromm 	return 0;
1246b2765275SChristian Gromm }
1247b2765275SChristian Gromm 
1248b2765275SChristian Gromm /**
1249b2765275SChristian Gromm  * most_deregister_component - deregisters a driver component with the core
1250b2765275SChristian Gromm  * @comp: driver component
1251b2765275SChristian Gromm  */
most_deregister_component(struct most_component * comp)1252b2765275SChristian Gromm int most_deregister_component(struct most_component *comp)
1253b2765275SChristian Gromm {
1254b2765275SChristian Gromm 	if (!comp) {
1255b2765275SChristian Gromm 		pr_err("Bad component\n");
1256b2765275SChristian Gromm 		return -EINVAL;
1257b2765275SChristian Gromm 	}
1258b2765275SChristian Gromm 
1259b2765275SChristian Gromm 	bus_for_each_dev(&mostbus, NULL, comp, disconnect_channels);
1260b2765275SChristian Gromm 	list_del(&comp->list);
1261b2765275SChristian Gromm 	return 0;
1262b2765275SChristian Gromm }
1263b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_deregister_component);
1264b2765275SChristian Gromm 
release_channel(struct device * dev)1265b2765275SChristian Gromm static void release_channel(struct device *dev)
1266b2765275SChristian Gromm {
1267b2765275SChristian Gromm 	struct most_channel *c = to_channel(dev);
1268b2765275SChristian Gromm 
1269b2765275SChristian Gromm 	kfree(c);
1270b2765275SChristian Gromm }
1271b2765275SChristian Gromm 
1272b2765275SChristian Gromm /**
1273b2765275SChristian Gromm  * most_register_interface - registers an interface with core
1274b2765275SChristian Gromm  * @iface: device interface
1275b2765275SChristian Gromm  *
1276b2765275SChristian Gromm  * Allocates and initializes a new interface instance and all of its channels.
1277b2765275SChristian Gromm  * Returns a pointer to kobject or an error pointer.
1278b2765275SChristian Gromm  */
most_register_interface(struct most_interface * iface)1279b2765275SChristian Gromm int most_register_interface(struct most_interface *iface)
1280b2765275SChristian Gromm {
1281b2765275SChristian Gromm 	unsigned int i;
1282b2765275SChristian Gromm 	int id;
1283b2765275SChristian Gromm 	struct most_channel *c;
1284b2765275SChristian Gromm 
1285b2765275SChristian Gromm 	if (!iface || !iface->enqueue || !iface->configure ||
1286e4463e49SColin Ian King 	    !iface->poison_channel || (iface->num_channels > MAX_CHANNELS))
1287b2765275SChristian Gromm 		return -EINVAL;
1288b2765275SChristian Gromm 
1289b737a221SChristophe JAILLET 	id = ida_alloc(&mdev_id, GFP_KERNEL);
1290b2765275SChristian Gromm 	if (id < 0) {
1291b2765275SChristian Gromm 		dev_err(iface->dev, "Failed to allocate device ID\n");
1292b2765275SChristian Gromm 		return id;
1293b2765275SChristian Gromm 	}
1294b2765275SChristian Gromm 
1295b2765275SChristian Gromm 	iface->p = kzalloc(sizeof(*iface->p), GFP_KERNEL);
1296b2765275SChristian Gromm 	if (!iface->p) {
1297b737a221SChristophe JAILLET 		ida_free(&mdev_id, id);
1298b2765275SChristian Gromm 		return -ENOMEM;
1299b2765275SChristian Gromm 	}
1300b2765275SChristian Gromm 
1301b2765275SChristian Gromm 	INIT_LIST_HEAD(&iface->p->channel_list);
1302b2765275SChristian Gromm 	iface->p->dev_id = id;
1303b2765275SChristian Gromm 	strscpy(iface->p->name, iface->description, sizeof(iface->p->name));
1304b2765275SChristian Gromm 	iface->dev->bus = &mostbus;
1305b2765275SChristian Gromm 	iface->dev->groups = interface_attr_groups;
1306b2765275SChristian Gromm 	dev_set_drvdata(iface->dev, iface);
1307b2765275SChristian Gromm 	if (device_register(iface->dev)) {
1308b2765275SChristian Gromm 		dev_err(iface->dev, "Failed to register interface device\n");
1309b2765275SChristian Gromm 		kfree(iface->p);
1310b2765275SChristian Gromm 		put_device(iface->dev);
1311b737a221SChristophe JAILLET 		ida_free(&mdev_id, id);
1312b2765275SChristian Gromm 		return -ENOMEM;
1313b2765275SChristian Gromm 	}
1314b2765275SChristian Gromm 
1315b2765275SChristian Gromm 	for (i = 0; i < iface->num_channels; i++) {
1316b2765275SChristian Gromm 		const char *name_suffix = iface->channel_vector[i].name_suffix;
1317b2765275SChristian Gromm 
1318b2765275SChristian Gromm 		c = kzalloc(sizeof(*c), GFP_KERNEL);
1319b2765275SChristian Gromm 		if (!c)
1320b2765275SChristian Gromm 			goto err_free_resources;
1321b2765275SChristian Gromm 		if (!name_suffix)
1322b2765275SChristian Gromm 			snprintf(c->name, STRING_SIZE, "ch%d", i);
1323b2765275SChristian Gromm 		else
1324b2765275SChristian Gromm 			snprintf(c->name, STRING_SIZE, "%s", name_suffix);
1325b2765275SChristian Gromm 		c->dev.init_name = c->name;
1326b2765275SChristian Gromm 		c->dev.parent = iface->dev;
1327b2765275SChristian Gromm 		c->dev.groups = channel_attr_groups;
1328b2765275SChristian Gromm 		c->dev.release = release_channel;
1329b2765275SChristian Gromm 		iface->p->channel[i] = c;
1330b2765275SChristian Gromm 		c->is_starving = 0;
1331b2765275SChristian Gromm 		c->iface = iface;
1332b2765275SChristian Gromm 		c->channel_id = i;
1333b2765275SChristian Gromm 		c->keep_mbo = false;
1334b2765275SChristian Gromm 		c->enqueue_halt = false;
1335b2765275SChristian Gromm 		c->is_poisoned = false;
1336b2765275SChristian Gromm 		c->cfg.direction = 0;
1337b2765275SChristian Gromm 		c->cfg.data_type = 0;
1338b2765275SChristian Gromm 		c->cfg.num_buffers = 0;
1339b2765275SChristian Gromm 		c->cfg.buffer_size = 0;
1340b2765275SChristian Gromm 		c->cfg.subbuffer_size = 0;
1341b2765275SChristian Gromm 		c->cfg.packets_per_xact = 0;
1342b2765275SChristian Gromm 		spin_lock_init(&c->fifo_lock);
1343b2765275SChristian Gromm 		INIT_LIST_HEAD(&c->fifo);
1344b2765275SChristian Gromm 		INIT_LIST_HEAD(&c->trash_fifo);
1345b2765275SChristian Gromm 		INIT_LIST_HEAD(&c->halt_fifo);
1346b2765275SChristian Gromm 		init_completion(&c->cleanup);
1347b2765275SChristian Gromm 		atomic_set(&c->mbo_ref, 0);
1348b2765275SChristian Gromm 		mutex_init(&c->start_mutex);
1349b2765275SChristian Gromm 		mutex_init(&c->nq_mutex);
1350b2765275SChristian Gromm 		list_add_tail(&c->list, &iface->p->channel_list);
1351b2765275SChristian Gromm 		if (device_register(&c->dev)) {
1352b2765275SChristian Gromm 			dev_err(&c->dev, "Failed to register channel device\n");
1353b2765275SChristian Gromm 			goto err_free_most_channel;
1354b2765275SChristian Gromm 		}
1355b2765275SChristian Gromm 	}
1356b2765275SChristian Gromm 	most_interface_register_notify(iface->description);
1357b2765275SChristian Gromm 	return 0;
1358b2765275SChristian Gromm 
1359b2765275SChristian Gromm err_free_most_channel:
1360b2765275SChristian Gromm 	put_device(&c->dev);
1361b2765275SChristian Gromm 
1362b2765275SChristian Gromm err_free_resources:
1363b2765275SChristian Gromm 	while (i > 0) {
1364b2765275SChristian Gromm 		c = iface->p->channel[--i];
1365b2765275SChristian Gromm 		device_unregister(&c->dev);
1366b2765275SChristian Gromm 	}
1367b2765275SChristian Gromm 	kfree(iface->p);
1368b2765275SChristian Gromm 	device_unregister(iface->dev);
1369b737a221SChristophe JAILLET 	ida_free(&mdev_id, id);
1370b2765275SChristian Gromm 	return -ENOMEM;
1371b2765275SChristian Gromm }
1372b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_register_interface);
1373b2765275SChristian Gromm 
1374b2765275SChristian Gromm /**
1375b2765275SChristian Gromm  * most_deregister_interface - deregisters an interface with core
1376b2765275SChristian Gromm  * @iface: device interface
1377b2765275SChristian Gromm  *
1378b2765275SChristian Gromm  * Before removing an interface instance from the list, all running
1379b2765275SChristian Gromm  * channels are stopped and poisoned.
1380b2765275SChristian Gromm  */
most_deregister_interface(struct most_interface * iface)1381b2765275SChristian Gromm void most_deregister_interface(struct most_interface *iface)
1382b2765275SChristian Gromm {
1383b2765275SChristian Gromm 	int i;
1384b2765275SChristian Gromm 	struct most_channel *c;
1385b2765275SChristian Gromm 
1386b2765275SChristian Gromm 	for (i = 0; i < iface->num_channels; i++) {
1387b2765275SChristian Gromm 		c = iface->p->channel[i];
1388b2765275SChristian Gromm 		if (c->pipe0.comp)
1389b2765275SChristian Gromm 			c->pipe0.comp->disconnect_channel(c->iface,
1390b2765275SChristian Gromm 							c->channel_id);
1391b2765275SChristian Gromm 		if (c->pipe1.comp)
1392b2765275SChristian Gromm 			c->pipe1.comp->disconnect_channel(c->iface,
1393b2765275SChristian Gromm 							c->channel_id);
1394b2765275SChristian Gromm 		c->pipe0.comp = NULL;
1395b2765275SChristian Gromm 		c->pipe1.comp = NULL;
1396b2765275SChristian Gromm 		list_del(&c->list);
1397b2765275SChristian Gromm 		device_unregister(&c->dev);
1398b2765275SChristian Gromm 	}
1399b2765275SChristian Gromm 
1400b737a221SChristophe JAILLET 	ida_free(&mdev_id, iface->p->dev_id);
1401b2765275SChristian Gromm 	kfree(iface->p);
1402b2765275SChristian Gromm 	device_unregister(iface->dev);
1403b2765275SChristian Gromm }
1404b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_deregister_interface);
1405b2765275SChristian Gromm 
1406b2765275SChristian Gromm /**
1407b2765275SChristian Gromm  * most_stop_enqueue - prevents core from enqueueing MBOs
1408b2765275SChristian Gromm  * @iface: pointer to interface
1409b2765275SChristian Gromm  * @id: channel id
1410b2765275SChristian Gromm  *
1411b2765275SChristian Gromm  * This is called by an HDM that _cannot_ attend to its duties and
1412b2765275SChristian Gromm  * is imminent to get run over by the core. The core is not going to
1413b2765275SChristian Gromm  * enqueue any further packets unless the flagging HDM calls
1414b2765275SChristian Gromm  * most_resume enqueue().
1415b2765275SChristian Gromm  */
most_stop_enqueue(struct most_interface * iface,int id)1416b2765275SChristian Gromm void most_stop_enqueue(struct most_interface *iface, int id)
1417b2765275SChristian Gromm {
1418b2765275SChristian Gromm 	struct most_channel *c = iface->p->channel[id];
1419b2765275SChristian Gromm 
1420b2765275SChristian Gromm 	if (!c)
1421b2765275SChristian Gromm 		return;
1422b2765275SChristian Gromm 
1423b2765275SChristian Gromm 	mutex_lock(&c->nq_mutex);
1424b2765275SChristian Gromm 	c->enqueue_halt = true;
1425b2765275SChristian Gromm 	mutex_unlock(&c->nq_mutex);
1426b2765275SChristian Gromm }
1427b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_stop_enqueue);
1428b2765275SChristian Gromm 
1429b2765275SChristian Gromm /**
1430b2765275SChristian Gromm  * most_resume_enqueue - allow core to enqueue MBOs again
1431b2765275SChristian Gromm  * @iface: pointer to interface
1432b2765275SChristian Gromm  * @id: channel id
1433b2765275SChristian Gromm  *
1434b2765275SChristian Gromm  * This clears the enqueue halt flag and enqueues all MBOs currently
1435b2765275SChristian Gromm  * sitting in the wait fifo.
1436b2765275SChristian Gromm  */
most_resume_enqueue(struct most_interface * iface,int id)1437b2765275SChristian Gromm void most_resume_enqueue(struct most_interface *iface, int id)
1438b2765275SChristian Gromm {
1439b2765275SChristian Gromm 	struct most_channel *c = iface->p->channel[id];
1440b2765275SChristian Gromm 
1441b2765275SChristian Gromm 	if (!c)
1442b2765275SChristian Gromm 		return;
1443b2765275SChristian Gromm 
1444b2765275SChristian Gromm 	mutex_lock(&c->nq_mutex);
1445b2765275SChristian Gromm 	c->enqueue_halt = false;
1446b2765275SChristian Gromm 	mutex_unlock(&c->nq_mutex);
1447b2765275SChristian Gromm 
1448b2765275SChristian Gromm 	wake_up_interruptible(&c->hdm_fifo_wq);
1449b2765275SChristian Gromm }
1450b2765275SChristian Gromm EXPORT_SYMBOL_GPL(most_resume_enqueue);
1451b2765275SChristian Gromm 
most_init(void)1452b2765275SChristian Gromm static int __init most_init(void)
1453b2765275SChristian Gromm {
1454b2765275SChristian Gromm 	int err;
1455b2765275SChristian Gromm 
1456b2765275SChristian Gromm 	INIT_LIST_HEAD(&comp_list);
1457b2765275SChristian Gromm 	ida_init(&mdev_id);
1458b2765275SChristian Gromm 
1459b2765275SChristian Gromm 	err = bus_register(&mostbus);
1460b2765275SChristian Gromm 	if (err) {
1461b2765275SChristian Gromm 		pr_err("Failed to register most bus\n");
1462b2765275SChristian Gromm 		return err;
1463b2765275SChristian Gromm 	}
1464b2765275SChristian Gromm 	err = driver_register(&mostbus_driver);
1465b2765275SChristian Gromm 	if (err) {
1466b2765275SChristian Gromm 		pr_err("Failed to register core driver\n");
1467b2765275SChristian Gromm 		goto err_unregister_bus;
1468b2765275SChristian Gromm 	}
1469b2765275SChristian Gromm 	configfs_init();
1470b2765275SChristian Gromm 	return 0;
1471b2765275SChristian Gromm 
1472b2765275SChristian Gromm err_unregister_bus:
1473b2765275SChristian Gromm 	bus_unregister(&mostbus);
1474b2765275SChristian Gromm 	return err;
1475b2765275SChristian Gromm }
1476b2765275SChristian Gromm 
most_exit(void)1477b2765275SChristian Gromm static void __exit most_exit(void)
1478b2765275SChristian Gromm {
1479b2765275SChristian Gromm 	driver_unregister(&mostbus_driver);
1480b2765275SChristian Gromm 	bus_unregister(&mostbus);
1481b2765275SChristian Gromm 	ida_destroy(&mdev_id);
1482b2765275SChristian Gromm }
1483b2765275SChristian Gromm 
14845e56bc06SChristian Gromm subsys_initcall(most_init);
1485b2765275SChristian Gromm module_exit(most_exit);
1486b2765275SChristian Gromm MODULE_LICENSE("GPL");
1487b2765275SChristian Gromm MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>");
1488b2765275SChristian Gromm MODULE_DESCRIPTION("Core module of stacked MOST Linux driver");
1489