int ipc_bit;
struct list_head channels;
- rwlock_t channels_lock;
+ spinlock_t channels_lock;
DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
struct work_struct state_work;
};
+/*
+ * SMD channel states.
+ */
+enum smd_channel_state {
+ SMD_CHANNEL_CLOSED,
+ SMD_CHANNEL_OPENING,
+ SMD_CHANNEL_OPENED,
+ SMD_CHANNEL_FLUSHING,
+ SMD_CHANNEL_CLOSING,
+ SMD_CHANNEL_RESET,
+ SMD_CHANNEL_RESET_OPENING
+};
+
+/**
+ * struct qcom_smd_channel - smd channel struct
+ * @edge: qcom_smd_edge this channel is living on
+ * @qsdev: reference to a associated smd client device
+ * @name: name of the channel
+ * @state: local state of the channel
+ * @remote_state: remote state of the channel
+ * @info: byte aligned outgoing/incoming channel info
+ * @info_word: word aligned outgoing/incoming channel info
+ * @tx_lock: lock to make writes to the channel mutually exclusive
+ * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR
+ * @tx_fifo: pointer to the outgoing ring buffer
+ * @rx_fifo: pointer to the incoming ring buffer
+ * @fifo_size: size of each ring buffer
+ * @bounce_buffer: bounce buffer for reading wrapped packets
+ * @cb: callback function registered for this channel
+ * @recv_lock: guard for rx info modifications and cb pointer
+ * @pkt_size: size of the currently handled packet
+ * @list: lite entry for @channels in qcom_smd_edge
+ */
+struct qcom_smd_channel {
+ struct qcom_smd_edge *edge;
+
+ struct qcom_smd_device *qsdev;
+
+ char *name;
+ enum smd_channel_state state;
+ enum smd_channel_state remote_state;
+
+ struct smd_channel_info_pair *info;
+ struct smd_channel_info_word_pair *info_word;
+
+ struct mutex tx_lock;
+ wait_queue_head_t fblockread_event;
+
+ void *tx_fifo;
+ void *rx_fifo;
+ int fifo_size;
+
+ void *bounce_buffer;
+ qcom_smd_cb_t cb;
+
+ spinlock_t recv_lock;
+
+ int pkt_size;
+
+ void *drvdata;
+
+ struct list_head list;
+ struct list_head dev_list;
+};
+
/**
* struct qcom_smd - smd struct
* @dev: device struct
struct qcom_smd_edge *edge = data;
struct qcom_smd_channel *channel;
unsigned available;
- bool kick_worker = false;
+ bool kick_scanner = false;
+ bool kick_state = false;
/*
* Handle state changes or data on each of the channels on this edge
*/
- read_lock(&edge->channels_lock);
+ spin_lock(&edge->channels_lock);
list_for_each_entry(channel, &edge->channels, list) {
spin_lock(&channel->recv_lock);
- kick_worker |= qcom_smd_channel_intr(channel);
+ kick_state |= qcom_smd_channel_intr(channel);
spin_unlock(&channel->recv_lock);
}
- read_unlock(&edge->channels_lock);
+ spin_unlock(&edge->channels_lock);
/*
* Creating a new channel requires allocating an smem entry, so we only
available = qcom_smem_get_free_space(edge->remote_pid);
if (available != edge->smem_available) {
edge->smem_available = available;
- kick_worker = true;
+ kick_scanner = true;
}
- if (kick_worker)
+ if (kick_scanner)
schedule_work(&edge->scan_work);
+ if (kick_state)
+ schedule_work(&edge->state_work);
return IRQ_HANDLED;
}
{
__le32 hdr[5] = { cpu_to_le32(len), };
int tlen = sizeof(hdr) + len;
- int ret, length;
+ int ret;
/* Word aligned channels only accept word size aligned data */
if (channel->info_word && len % 4)
if (tlen >= channel->fifo_size)
return -EINVAL;
- length = qcom_smd_get_tx_avail(channel);
-
ret = mutex_lock_interruptible(&channel->tx_lock);
if (ret)
return ret;
- length = qcom_smd_get_tx_avail(channel);
while (qcom_smd_get_tx_avail(channel) < tlen) {
if (channel->state != SMD_CHANNEL_OPENED) {
ret = -EPIPE;
SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
- length = qcom_smd_get_tx_avail(channel);
qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
qcom_smd_write_fifo(channel, data, len);
{
struct qcom_smd_channel *channel;
struct qcom_smd_channel *ret = NULL;
+ unsigned long flags;
unsigned state;
- read_lock(&edge->channels_lock);
+ spin_lock_irqsave(&edge->channels_lock, flags);
list_for_each_entry(channel, &edge->channels, list) {
if (strcmp(channel->name, name))
continue;
ret = channel;
break;
}
- read_unlock(&edge->channels_lock);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
return ret;
}
/* The channel consist of a rx and tx fifo of equal size */
fifo_size /= 2;
- dev_err(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+ dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
name, info_size, fifo_size);
channel->tx_fifo = fifo_base;
if (IS_ERR(channel))
continue;
- write_lock_irqsave(&edge->channels_lock, flags);
+ spin_lock_irqsave(&edge->channels_lock, flags);
list_add(&channel->list, &edge->channels);
- write_unlock_irqrestore(&edge->channels_lock, flags);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
set_bit(i, edge->allocated[tbl]);
struct qcom_smd_edge,
state_work);
unsigned remote_state;
+ unsigned long flags;
/*
* Register a device for any closed channel where the remote processor
* is showing interest in opening the channel.
*/
- read_lock(&edge->channels_lock);
+ spin_lock_irqsave(&edge->channels_lock, flags);
list_for_each_entry(channel, &edge->channels, list) {
if (channel->state != SMD_CHANNEL_CLOSED)
continue;
remote_state != SMD_CHANNEL_OPENED)
continue;
- read_unlock(&edge->channels_lock);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
qcom_smd_create_device(channel);
- read_lock(&edge->channels_lock);
+ spin_lock_irqsave(&edge->channels_lock, flags);
}
/*
remote_state == SMD_CHANNEL_OPENED)
continue;
- read_unlock(&edge->channels_lock);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
qcom_smd_destroy_device(channel);
- read_lock(&edge->channels_lock);
+ spin_lock_irqsave(&edge->channels_lock, flags);
}
- read_unlock(&edge->channels_lock);
+ spin_unlock_irqrestore(&edge->channels_lock, flags);
}
/*
int ret;
INIT_LIST_HEAD(&edge->channels);
- rwlock_init(&edge->channels_lock);
+ spin_lock_init(&edge->channels_lock);
INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
INIT_WORK(&edge->state_work, qcom_channel_state_worker);
#include <linux/mod_devicetable.h>
struct qcom_smd;
+struct qcom_smd_channel;
struct qcom_smd_lookup;
-struct qcom_smd_device;
-
-/*
- * SMD channel states.
- */
-enum smd_channel_state {
- SMD_CHANNEL_CLOSED,
- SMD_CHANNEL_OPENING,
- SMD_CHANNEL_OPENED,
- SMD_CHANNEL_FLUSHING,
- SMD_CHANNEL_CLOSING,
- SMD_CHANNEL_RESET,
- SMD_CHANNEL_RESET_OPENING
-};
-
-/**
- * struct qcom_smd_channel - smd channel struct
- * @edge: qcom_smd_edge this channel is living on
- * @qsdev: reference to a associated smd client device
- * @name: name of the channel
- * @state: local state of the channel
- * @remote_state: remote state of the channel
- * @info: byte aligned outgoing/incoming channel info
- * @info_word: word aligned outgoing/incoming channel info
- * @tx_lock: lock to make writes to the channel mutually exclusive
- * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR
- * @tx_fifo: pointer to the outgoing ring buffer
- * @rx_fifo: pointer to the incoming ring buffer
- * @fifo_size: size of each ring buffer
- * @bounce_buffer: bounce buffer for reading wrapped packets
- * @cb: callback function registered for this channel
- * @recv_lock: guard for rx info modifications and cb pointer
- * @pkt_size: size of the currently handled packet
- * @list: lite entry for @channels in qcom_smd_edge
- */
-
-struct qcom_smd_channel {
- struct qcom_smd_edge *edge;
-
- struct qcom_smd_device *qsdev;
-
- char *name;
- enum smd_channel_state state;
- enum smd_channel_state remote_state;
-
- struct smd_channel_info_pair *info;
- struct smd_channel_info_word_pair *info_word;
-
- struct mutex tx_lock;
- wait_queue_head_t fblockread_event;
-
- void *tx_fifo;
- void *rx_fifo;
- int fifo_size;
-
- void *bounce_buffer;
- qcom_smd_cb_t cb;
-
- spinlock_t recv_lock;
-
- int pkt_size;
-
- struct list_head list;
- struct list_head dev_list;
-};
/**
* struct qcom_smd_id - struct used for matching a smd device
qcom_smd_cb_t callback;
};
+#if IS_ENABLED(CONFIG_QCOM_SMD)
+
int qcom_smd_driver_register(struct qcom_smd_driver *drv);
void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
+struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
+ const char *name,
+ qcom_smd_cb_t cb);
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
+int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
+
+
+#else
+
+static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
+{
+ return -ENXIO;
+}
+
+static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline struct qcom_smd_channel *
+qcom_smd_open_channel(struct qcom_smd_channel *channel,
+ const char *name,
+ qcom_smd_cb_t cb)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+ return NULL;
+}
+
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+ return NULL;
+}
+
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline int qcom_smd_send(struct qcom_smd_channel *channel,
+ const void *data, int len)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+ return -ENXIO;
+}
+
+#endif
#define module_qcom_smd_driver(__smd_driver) \
module_driver(__smd_driver, qcom_smd_driver_register, \
qcom_smd_driver_unregister)
-int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
-
-struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
- const char *name,
- qcom_smd_cb_t cb);
#endif