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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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 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 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 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 494b2765275SChristian Gromm static int most_match(struct device *dev, 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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 */ 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 1289*b737a221SChristophe 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) { 1297*b737a221SChristophe 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); 1311*b737a221SChristophe 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); 1369*b737a221SChristophe 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 */ 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 1400*b737a221SChristophe 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 */ 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 */ 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 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 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