提交 08a6ee58 编写于 作者: D David S. Miller

Merge tag 'net-next-qcom-soc-4.7-2-merge' of git://github.com/andersson/kernel

Merge tag 'qcom-soc-for-4.7-2' into net-next

This merges the Qualcomm SOC tree with the net-next, solving the
merge conflict in the SMD API between the two.
...@@ -1470,7 +1470,10 @@ F: arch/arm/boot/dts/qcom-*.dts ...@@ -1470,7 +1470,10 @@ F: arch/arm/boot/dts/qcom-*.dts
F: arch/arm/boot/dts/qcom-*.dtsi F: arch/arm/boot/dts/qcom-*.dtsi
F: arch/arm/mach-qcom/ F: arch/arm/mach-qcom/
F: arch/arm64/boot/dts/qcom/* F: arch/arm64/boot/dts/qcom/*
F: drivers/i2c/busses/i2c-qup.c
F: drivers/clk/qcom/
F: drivers/soc/qcom/ F: drivers/soc/qcom/
F: drivers/spi/spi-qup.c
F: drivers/tty/serial/msm_serial.h F: drivers/tty/serial/msm_serial.h
F: drivers/tty/serial/msm_serial.c F: drivers/tty/serial/msm_serial.c
F: drivers/*/pm8???-* F: drivers/*/pm8???-*
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
*/ */
struct qcom_smd_rpm { struct qcom_smd_rpm {
struct qcom_smd_channel *rpm_channel; struct qcom_smd_channel *rpm_channel;
struct device *dev;
struct completion ack; struct completion ack;
struct mutex lock; struct mutex lock;
...@@ -149,14 +150,14 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, ...@@ -149,14 +150,14 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
} }
EXPORT_SYMBOL(qcom_rpm_smd_write); EXPORT_SYMBOL(qcom_rpm_smd_write);
static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev, static int qcom_smd_rpm_callback(struct qcom_smd_channel *channel,
const void *data, const void *data,
size_t count) size_t count)
{ {
const struct qcom_rpm_header *hdr = data; const struct qcom_rpm_header *hdr = data;
size_t hdr_length = le32_to_cpu(hdr->length); size_t hdr_length = le32_to_cpu(hdr->length);
const struct qcom_rpm_message *msg; const struct qcom_rpm_message *msg;
struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev); struct qcom_smd_rpm *rpm = qcom_smd_get_drvdata(channel);
const u8 *buf = data + sizeof(struct qcom_rpm_header); const u8 *buf = data + sizeof(struct qcom_rpm_header);
const u8 *end = buf + hdr_length; const u8 *end = buf + hdr_length;
char msgbuf[32]; char msgbuf[32];
...@@ -165,7 +166,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev, ...@@ -165,7 +166,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST || if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST ||
hdr_length < sizeof(struct qcom_rpm_message)) { hdr_length < sizeof(struct qcom_rpm_message)) {
dev_err(&qsdev->dev, "invalid request\n"); dev_err(rpm->dev, "invalid request\n");
return 0; return 0;
} }
...@@ -206,7 +207,9 @@ static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev) ...@@ -206,7 +207,9 @@ static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev)
mutex_init(&rpm->lock); mutex_init(&rpm->lock);
init_completion(&rpm->ack); init_completion(&rpm->ack);
rpm->dev = &sdev->dev;
rpm->rpm_channel = sdev->channel; rpm->rpm_channel = sdev->channel;
qcom_smd_set_drvdata(sdev->channel, rpm);
dev_set_drvdata(&sdev->dev, rpm); dev_set_drvdata(&sdev->dev, rpm);
......
...@@ -106,9 +106,9 @@ static const struct { ...@@ -106,9 +106,9 @@ static const struct {
* @channels: list of all channels detected on this edge * @channels: list of all channels detected on this edge
* @channels_lock: guard for modifications of @channels * @channels_lock: guard for modifications of @channels
* @allocated: array of bitmaps representing already allocated channels * @allocated: array of bitmaps representing already allocated channels
* @need_rescan: flag that the @work needs to scan smem for new channels
* @smem_available: last available amount of smem triggering a channel scan * @smem_available: last available amount of smem triggering a channel scan
* @work: work item for edge house keeping * @scan_work: work item for discovering new channels
* @state_work: work item for edge state changes
*/ */
struct qcom_smd_edge { struct qcom_smd_edge {
struct qcom_smd *smd; struct qcom_smd *smd;
...@@ -127,10 +127,12 @@ struct qcom_smd_edge { ...@@ -127,10 +127,12 @@ struct qcom_smd_edge {
DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE); DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
bool need_rescan;
unsigned smem_available; unsigned smem_available;
struct work_struct work; wait_queue_head_t new_channel_event;
struct work_struct scan_work;
struct work_struct state_work;
}; };
/* /*
...@@ -186,13 +188,16 @@ struct qcom_smd_channel { ...@@ -186,13 +188,16 @@ struct qcom_smd_channel {
int fifo_size; int fifo_size;
void *bounce_buffer; void *bounce_buffer;
int (*cb)(struct qcom_smd_device *, const void *, size_t); qcom_smd_cb_t cb;
spinlock_t recv_lock; spinlock_t recv_lock;
int pkt_size; int pkt_size;
void *drvdata;
struct list_head list; struct list_head list;
struct list_head dev_list;
}; };
/** /**
...@@ -377,6 +382,19 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel) ...@@ -377,6 +382,19 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
channel->pkt_size = 0; channel->pkt_size = 0;
} }
/*
* Set the callback for a channel, with appropriate locking
*/
static void qcom_smd_channel_set_callback(struct qcom_smd_channel *channel,
qcom_smd_cb_t cb)
{
unsigned long flags;
spin_lock_irqsave(&channel->recv_lock, flags);
channel->cb = cb;
spin_unlock_irqrestore(&channel->recv_lock, flags);
};
/* /*
* Calculate the amount of data available in the rx fifo * Calculate the amount of data available in the rx fifo
*/ */
...@@ -497,7 +515,6 @@ static void qcom_smd_channel_advance(struct qcom_smd_channel *channel, ...@@ -497,7 +515,6 @@ static void qcom_smd_channel_advance(struct qcom_smd_channel *channel,
*/ */
static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel) static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
{ {
struct qcom_smd_device *qsdev = channel->qsdev;
unsigned tail; unsigned tail;
size_t len; size_t len;
void *ptr; void *ptr;
...@@ -517,7 +534,7 @@ static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel) ...@@ -517,7 +534,7 @@ static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
len = channel->pkt_size; len = channel->pkt_size;
} }
ret = channel->cb(qsdev, ptr, len); ret = channel->cb(channel, ptr, len);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -601,7 +618,8 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) ...@@ -601,7 +618,8 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
struct qcom_smd_edge *edge = data; struct qcom_smd_edge *edge = data;
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
unsigned available; 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 * Handle state changes or data on each of the channels on this edge
...@@ -609,7 +627,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) ...@@ -609,7 +627,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
spin_lock(&edge->channels_lock); spin_lock(&edge->channels_lock);
list_for_each_entry(channel, &edge->channels, list) { list_for_each_entry(channel, &edge->channels, list) {
spin_lock(&channel->recv_lock); spin_lock(&channel->recv_lock);
kick_worker |= qcom_smd_channel_intr(channel); kick_state |= qcom_smd_channel_intr(channel);
spin_unlock(&channel->recv_lock); spin_unlock(&channel->recv_lock);
} }
spin_unlock(&edge->channels_lock); spin_unlock(&edge->channels_lock);
...@@ -622,12 +640,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) ...@@ -622,12 +640,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
available = qcom_smem_get_free_space(edge->remote_pid); available = qcom_smem_get_free_space(edge->remote_pid);
if (available != edge->smem_available) { if (available != edge->smem_available) {
edge->smem_available = available; edge->smem_available = available;
edge->need_rescan = true; kick_scanner = true;
kick_worker = true;
} }
if (kick_worker) if (kick_scanner)
schedule_work(&edge->work); schedule_work(&edge->scan_work);
if (kick_state)
schedule_work(&edge->state_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -793,18 +812,12 @@ static int qcom_smd_dev_match(struct device *dev, struct device_driver *drv) ...@@ -793,18 +812,12 @@ static int qcom_smd_dev_match(struct device *dev, struct device_driver *drv)
} }
/* /*
* Probe the smd client. * Helper for opening a channel
*
* The remote side have indicated that it want the channel to be opened, so
* complete the state handshake and probe our client driver.
*/ */
static int qcom_smd_dev_probe(struct device *dev) static int qcom_smd_channel_open(struct qcom_smd_channel *channel,
qcom_smd_cb_t cb)
{ {
struct qcom_smd_device *qsdev = to_smd_device(dev);
struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
struct qcom_smd_channel *channel = qsdev->channel;
size_t bb_size; size_t bb_size;
int ret;
/* /*
* Packets are maximum 4k, but reduce if the fifo is smaller * Packets are maximum 4k, but reduce if the fifo is smaller
...@@ -814,12 +827,44 @@ static int qcom_smd_dev_probe(struct device *dev) ...@@ -814,12 +827,44 @@ static int qcom_smd_dev_probe(struct device *dev)
if (!channel->bounce_buffer) if (!channel->bounce_buffer)
return -ENOMEM; return -ENOMEM;
channel->cb = qsdrv->callback; qcom_smd_channel_set_callback(channel, cb);
qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING); qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING);
qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED); qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED);
return 0;
}
/*
* Helper for closing and resetting a channel
*/
static void qcom_smd_channel_close(struct qcom_smd_channel *channel)
{
qcom_smd_channel_set_callback(channel, NULL);
kfree(channel->bounce_buffer);
channel->bounce_buffer = NULL;
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);
qcom_smd_channel_reset(channel);
}
/*
* Probe the smd client.
*
* The remote side have indicated that it want the channel to be opened, so
* complete the state handshake and probe our client driver.
*/
static int qcom_smd_dev_probe(struct device *dev)
{
struct qcom_smd_device *qsdev = to_smd_device(dev);
struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
struct qcom_smd_channel *channel = qsdev->channel;
int ret;
ret = qcom_smd_channel_open(channel, qsdrv->callback);
if (ret)
return ret;
ret = qsdrv->probe(qsdev); ret = qsdrv->probe(qsdev);
if (ret) if (ret)
goto err; goto err;
...@@ -831,11 +876,7 @@ static int qcom_smd_dev_probe(struct device *dev) ...@@ -831,11 +876,7 @@ static int qcom_smd_dev_probe(struct device *dev)
err: err:
dev_err(&qsdev->dev, "probe failed\n"); dev_err(&qsdev->dev, "probe failed\n");
channel->cb = NULL; qcom_smd_channel_close(channel);
kfree(channel->bounce_buffer);
channel->bounce_buffer = NULL;
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);
return ret; return ret;
} }
...@@ -850,16 +891,15 @@ static int qcom_smd_dev_remove(struct device *dev) ...@@ -850,16 +891,15 @@ static int qcom_smd_dev_remove(struct device *dev)
struct qcom_smd_device *qsdev = to_smd_device(dev); struct qcom_smd_device *qsdev = to_smd_device(dev);
struct qcom_smd_driver *qsdrv = to_smd_driver(dev); struct qcom_smd_driver *qsdrv = to_smd_driver(dev);
struct qcom_smd_channel *channel = qsdev->channel; struct qcom_smd_channel *channel = qsdev->channel;
unsigned long flags; struct qcom_smd_channel *tmp;
struct qcom_smd_channel *ch;
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING); qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING);
/* /*
* Make sure we don't race with the code receiving data. * Make sure we don't race with the code receiving data.
*/ */
spin_lock_irqsave(&channel->recv_lock, flags); qcom_smd_channel_set_callback(channel, NULL);
channel->cb = NULL;
spin_unlock_irqrestore(&channel->recv_lock, flags);
/* Wake up any sleepers in qcom_smd_send() */ /* Wake up any sleepers in qcom_smd_send() */
wake_up_interruptible(&channel->fblockread_event); wake_up_interruptible(&channel->fblockread_event);
...@@ -872,15 +912,14 @@ static int qcom_smd_dev_remove(struct device *dev) ...@@ -872,15 +912,14 @@ static int qcom_smd_dev_remove(struct device *dev)
qsdrv->remove(qsdev); qsdrv->remove(qsdev);
/* /*
* The client is now gone, cleanup and reset the channel state. * The client is now gone, close and release all channels associated
* with this sdev
*/ */
channel->qsdev = NULL; list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
kfree(channel->bounce_buffer); qcom_smd_channel_close(ch);
channel->bounce_buffer = NULL; list_del(&ch->dev_list);
ch->qsdev = NULL;
qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); }
qcom_smd_channel_reset(channel);
return 0; return 0;
} }
...@@ -996,6 +1035,18 @@ int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv) ...@@ -996,6 +1035,18 @@ int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv)
} }
EXPORT_SYMBOL(qcom_smd_driver_register); EXPORT_SYMBOL(qcom_smd_driver_register);
void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
{
return channel->drvdata;
}
EXPORT_SYMBOL(qcom_smd_get_drvdata);
void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
{
channel->drvdata = data;
}
EXPORT_SYMBOL(qcom_smd_set_drvdata);
/** /**
* qcom_smd_driver_unregister - unregister a smd driver * qcom_smd_driver_unregister - unregister a smd driver
* @qsdrv: qcom_smd_driver struct * @qsdrv: qcom_smd_driver struct
...@@ -1006,6 +1057,78 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv) ...@@ -1006,6 +1057,78 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv)
} }
EXPORT_SYMBOL(qcom_smd_driver_unregister); EXPORT_SYMBOL(qcom_smd_driver_unregister);
static struct qcom_smd_channel *
qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
{
struct qcom_smd_channel *channel;
struct qcom_smd_channel *ret = NULL;
unsigned long flags;
unsigned state;
spin_lock_irqsave(&edge->channels_lock, flags);
list_for_each_entry(channel, &edge->channels, list) {
if (strcmp(channel->name, name))
continue;
state = GET_RX_CHANNEL_INFO(channel, state);
if (state != SMD_CHANNEL_OPENING &&
state != SMD_CHANNEL_OPENED)
continue;
ret = channel;
break;
}
spin_unlock_irqrestore(&edge->channels_lock, flags);
return ret;
}
/**
* qcom_smd_open_channel() - claim additional channels on the same edge
* @sdev: smd_device handle
* @name: channel name
* @cb: callback method to use for incoming data
*
* Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
* ready.
*/
struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
const char *name,
qcom_smd_cb_t cb)
{
struct qcom_smd_channel *channel;
struct qcom_smd_device *sdev = parent->qsdev;
struct qcom_smd_edge *edge = parent->edge;
int ret;
/* Wait up to HZ for the channel to appear */
ret = wait_event_interruptible_timeout(edge->new_channel_event,
(channel = qcom_smd_find_channel(edge, name)) != NULL,
HZ);
if (!ret)
return ERR_PTR(-ETIMEDOUT);
if (channel->state != SMD_CHANNEL_CLOSED) {
dev_err(&sdev->dev, "channel %s is busy\n", channel->name);
return ERR_PTR(-EBUSY);
}
channel->qsdev = sdev;
ret = qcom_smd_channel_open(channel, cb);
if (ret) {
channel->qsdev = NULL;
return ERR_PTR(ret);
}
/*
* Append the list of channel to the channels associated with the sdev
*/
list_add_tail(&channel->dev_list, &sdev->channel->dev_list);
return channel;
}
EXPORT_SYMBOL(qcom_smd_open_channel);
/* /*
* Allocate the qcom_smd_channel object for a newly found smd channel, * Allocate the qcom_smd_channel object for a newly found smd channel,
* retrieving and validating the smem items involved. * retrieving and validating the smem items involved.
...@@ -1027,6 +1150,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed ...@@ -1027,6 +1150,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
if (!channel) if (!channel)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&channel->dev_list);
channel->edge = edge; channel->edge = edge;
channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
if (!channel->name) if (!channel->name)
...@@ -1089,8 +1213,9 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed ...@@ -1089,8 +1213,9 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
* qcom_smd_create_channel() to create representations of these and add * qcom_smd_create_channel() to create representations of these and add
* them to the edge's list of channels. * them to the edge's list of channels.
*/ */
static void qcom_discover_channels(struct qcom_smd_edge *edge) static void qcom_channel_scan_worker(struct work_struct *work)
{ {
struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge, scan_work);
struct qcom_smd_alloc_entry *alloc_tbl; struct qcom_smd_alloc_entry *alloc_tbl;
struct qcom_smd_alloc_entry *entry; struct qcom_smd_alloc_entry *entry;
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
...@@ -1140,10 +1265,12 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge) ...@@ -1140,10 +1265,12 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge)
dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
set_bit(i, edge->allocated[tbl]); set_bit(i, edge->allocated[tbl]);
wake_up_interruptible(&edge->new_channel_event);
} }
} }
schedule_work(&edge->work); schedule_work(&edge->state_work);
} }
/* /*
...@@ -1151,29 +1278,23 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge) ...@@ -1151,29 +1278,23 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge)
* then scans all registered channels for state changes that should be handled * then scans all registered channels for state changes that should be handled
* by creating or destroying smd client devices for the registered channels. * by creating or destroying smd client devices for the registered channels.
* *
* LOCKING: edge->channels_lock is not needed to be held during the traversal * LOCKING: edge->channels_lock only needs to cover the list operations, as the
* of the channels list as it's done synchronously with the only writer. * worker is killed before any channels are deallocated
*/ */
static void qcom_channel_state_worker(struct work_struct *work) static void qcom_channel_state_worker(struct work_struct *work)
{ {
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
struct qcom_smd_edge *edge = container_of(work, struct qcom_smd_edge *edge = container_of(work,
struct qcom_smd_edge, struct qcom_smd_edge,
work); state_work);
unsigned remote_state; unsigned remote_state;
unsigned long flags;
/*
* Rescan smem if we have reason to belive that there are new channels.
*/
if (edge->need_rescan) {
edge->need_rescan = false;
qcom_discover_channels(edge);
}
/* /*
* Register a device for any closed channel where the remote processor * Register a device for any closed channel where the remote processor
* is showing interest in opening the channel. * is showing interest in opening the channel.
*/ */
spin_lock_irqsave(&edge->channels_lock, flags);
list_for_each_entry(channel, &edge->channels, list) { list_for_each_entry(channel, &edge->channels, list) {
if (channel->state != SMD_CHANNEL_CLOSED) if (channel->state != SMD_CHANNEL_CLOSED)
continue; continue;
...@@ -1183,7 +1304,9 @@ static void qcom_channel_state_worker(struct work_struct *work) ...@@ -1183,7 +1304,9 @@ static void qcom_channel_state_worker(struct work_struct *work)
remote_state != SMD_CHANNEL_OPENED) remote_state != SMD_CHANNEL_OPENED)
continue; continue;
spin_unlock_irqrestore(&edge->channels_lock, flags);
qcom_smd_create_device(channel); qcom_smd_create_device(channel);
spin_lock_irqsave(&edge->channels_lock, flags);
} }
/* /*
...@@ -1200,8 +1323,11 @@ static void qcom_channel_state_worker(struct work_struct *work) ...@@ -1200,8 +1323,11 @@ static void qcom_channel_state_worker(struct work_struct *work)
remote_state == SMD_CHANNEL_OPENED) remote_state == SMD_CHANNEL_OPENED)
continue; continue;
spin_unlock_irqrestore(&edge->channels_lock, flags);
qcom_smd_destroy_device(channel); qcom_smd_destroy_device(channel);
spin_lock_irqsave(&edge->channels_lock, flags);
} }
spin_unlock_irqrestore(&edge->channels_lock, flags);
} }
/* /*
...@@ -1219,7 +1345,8 @@ static int qcom_smd_parse_edge(struct device *dev, ...@@ -1219,7 +1345,8 @@ static int qcom_smd_parse_edge(struct device *dev,
INIT_LIST_HEAD(&edge->channels); INIT_LIST_HEAD(&edge->channels);
spin_lock_init(&edge->channels_lock); spin_lock_init(&edge->channels_lock);
INIT_WORK(&edge->work, qcom_channel_state_worker); INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
INIT_WORK(&edge->state_work, qcom_channel_state_worker);
edge->of_node = of_node_get(node); edge->of_node = of_node_get(node);
...@@ -1303,13 +1430,13 @@ static int qcom_smd_probe(struct platform_device *pdev) ...@@ -1303,13 +1430,13 @@ static int qcom_smd_probe(struct platform_device *pdev)
for_each_available_child_of_node(pdev->dev.of_node, node) { for_each_available_child_of_node(pdev->dev.of_node, node) {
edge = &smd->edges[i++]; edge = &smd->edges[i++];
edge->smd = smd; edge->smd = smd;
init_waitqueue_head(&edge->new_channel_event);
ret = qcom_smd_parse_edge(&pdev->dev, node, edge); ret = qcom_smd_parse_edge(&pdev->dev, node, edge);
if (ret) if (ret)
continue; continue;
edge->need_rescan = true; schedule_work(&edge->scan_work);
schedule_work(&edge->work);
} }
platform_set_drvdata(pdev, smd); platform_set_drvdata(pdev, smd);
...@@ -1332,8 +1459,10 @@ static int qcom_smd_remove(struct platform_device *pdev) ...@@ -1332,8 +1459,10 @@ static int qcom_smd_remove(struct platform_device *pdev)
edge = &smd->edges[i]; edge = &smd->edges[i];
disable_irq(edge->irq); disable_irq(edge->irq);
cancel_work_sync(&edge->work); cancel_work_sync(&edge->scan_work);
cancel_work_sync(&edge->state_work);
/* No need to lock here, because the writer is gone */
list_for_each_entry(channel, &edge->channels, list) { list_for_each_entry(channel, &edge->channels, list) {
if (!channel->qsdev) if (!channel->qsdev)
continue; continue;
......
...@@ -684,8 +684,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, ...@@ -684,8 +684,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
smem->regions[i].aux_base = (u32)r.start; smem->regions[i].aux_base = (u32)r.start;
smem->regions[i].size = resource_size(&r); smem->regions[i].size = resource_size(&r);
smem->regions[i].virt_base = devm_ioremap_nocache(dev, r.start, smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
resource_size(&r));
if (!smem->regions[i].virt_base) if (!smem->regions[i].virt_base)
return -ENOMEM; return -ENOMEM;
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
* Copyright (c) 2014,2015, Linaro Ltd. * Copyright (c) 2014,2015, Linaro Ltd.
* *
* SAW power controller driver
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation. * only version 2 as published by the Free Software Foundation.
...@@ -12,7 +14,6 @@ ...@@ -12,7 +14,6 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -378,8 +379,5 @@ static struct platform_driver spm_driver = { ...@@ -378,8 +379,5 @@ static struct platform_driver spm_driver = {
.of_match_table = spm_match_table, .of_match_table = spm_match_table,
}, },
}; };
module_platform_driver(spm_driver);
MODULE_LICENSE("GPL v2"); builtin_platform_driver(spm_driver);
MODULE_DESCRIPTION("SAW power controller driver");
MODULE_ALIAS("platform:saw");
...@@ -100,17 +100,17 @@ struct wcnss_download_nv_resp { ...@@ -100,17 +100,17 @@ struct wcnss_download_nv_resp {
/** /**
* wcnss_ctrl_smd_callback() - handler from SMD responses * wcnss_ctrl_smd_callback() - handler from SMD responses
* @qsdev: smd device handle * @channel: smd channel handle
* @data: pointer to the incoming data packet * @data: pointer to the incoming data packet
* @count: size of the incoming data packet * @count: size of the incoming data packet
* *
* Handles any incoming packets from the remote WCNSS_CTRL service. * Handles any incoming packets from the remote WCNSS_CTRL service.
*/ */
static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev, static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
const void *data, const void *data,
size_t count) size_t count)
{ {
struct wcnss_ctrl *wcnss = dev_get_drvdata(&qsdev->dev); struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(channel);
const struct wcnss_download_nv_resp *nvresp; const struct wcnss_download_nv_resp *nvresp;
const struct wcnss_version_resp *version; const struct wcnss_version_resp *version;
const struct wcnss_msg_hdr *hdr = data; const struct wcnss_msg_hdr *hdr = data;
...@@ -246,7 +246,7 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev) ...@@ -246,7 +246,7 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
init_completion(&wcnss->ack); init_completion(&wcnss->ack);
INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv); INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv);
dev_set_drvdata(&sdev->dev, wcnss); qcom_smd_set_drvdata(sdev->channel, wcnss);
return wcnss_request_version(wcnss); return wcnss_request_version(wcnss);
} }
......
...@@ -26,6 +26,8 @@ struct qcom_smd_device { ...@@ -26,6 +26,8 @@ struct qcom_smd_device {
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
}; };
typedef int (*qcom_smd_cb_t)(struct qcom_smd_channel *, const void *, size_t);
/** /**
* struct qcom_smd_driver - smd driver struct * struct qcom_smd_driver - smd driver struct
* @driver: underlying device driver * @driver: underlying device driver
...@@ -42,7 +44,7 @@ struct qcom_smd_driver { ...@@ -42,7 +44,7 @@ struct qcom_smd_driver {
int (*probe)(struct qcom_smd_device *dev); int (*probe)(struct qcom_smd_device *dev);
void (*remove)(struct qcom_smd_device *dev); void (*remove)(struct qcom_smd_device *dev);
int (*callback)(struct qcom_smd_device *, const void *, size_t); qcom_smd_cb_t callback;
}; };
#if IS_ENABLED(CONFIG_QCOM_SMD) #if IS_ENABLED(CONFIG_QCOM_SMD)
...@@ -50,8 +52,14 @@ struct qcom_smd_driver { ...@@ -50,8 +52,14 @@ struct qcom_smd_driver {
int qcom_smd_driver_register(struct qcom_smd_driver *drv); int qcom_smd_driver_register(struct qcom_smd_driver *drv);
void qcom_smd_driver_unregister(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); int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
#else #else
static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv) static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
...@@ -65,6 +73,29 @@ static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv) ...@@ -65,6 +73,29 @@ static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv)
WARN_ON(1); 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, static inline int qcom_smd_send(struct qcom_smd_channel *channel,
const void *data, int len) const void *data, int len)
{ {
......
#ifndef __QCOM_SMEM_STATE__ #ifndef __QCOM_SMEM_STATE__
#define __QCOM_SMEM_STATE__ #define __QCOM_SMEM_STATE__
#include <linux/errno.h>
struct device_node;
struct qcom_smem_state; struct qcom_smem_state;
struct qcom_smem_state_ops { struct qcom_smem_state_ops {
int (*update_bits)(void *, u32, u32); int (*update_bits)(void *, u32, u32);
}; };
#ifdef CONFIG_QCOM_SMEM_STATE
struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit); struct qcom_smem_state *qcom_smem_state_get(struct device *dev, const char *con_id, unsigned *bit);
void qcom_smem_state_put(struct qcom_smem_state *); void qcom_smem_state_put(struct qcom_smem_state *);
...@@ -15,4 +20,34 @@ int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 val ...@@ -15,4 +20,34 @@ int qcom_smem_state_update_bits(struct qcom_smem_state *state, u32 mask, u32 val
struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node, const struct qcom_smem_state_ops *ops, void *data); struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node, const struct qcom_smem_state_ops *ops, void *data);
void qcom_smem_state_unregister(struct qcom_smem_state *state); void qcom_smem_state_unregister(struct qcom_smem_state *state);
#else
static inline struct qcom_smem_state *qcom_smem_state_get(struct device *dev,
const char *con_id, unsigned *bit)
{
return ERR_PTR(-EINVAL);
}
static inline void qcom_smem_state_put(struct qcom_smem_state *state)
{
}
static inline int qcom_smem_state_update_bits(struct qcom_smem_state *state,
u32 mask, u32 value)
{
return -EINVAL;
}
static inline struct qcom_smem_state *qcom_smem_state_register(struct device_node *of_node,
const struct qcom_smem_state_ops *ops, void *data)
{
return ERR_PTR(-EINVAL);
}
static inline void qcom_smem_state_unregister(struct qcom_smem_state *state)
{
}
#endif
#endif #endif
...@@ -21,13 +21,14 @@ ...@@ -21,13 +21,14 @@
struct qrtr_smd_dev { struct qrtr_smd_dev {
struct qrtr_endpoint ep; struct qrtr_endpoint ep;
struct qcom_smd_channel *channel; struct qcom_smd_channel *channel;
struct device *dev;
}; };
/* from smd to qrtr */ /* from smd to qrtr */
static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev, static int qcom_smd_qrtr_callback(struct qcom_smd_channel *channel,
const void *data, size_t len) const void *data, size_t len)
{ {
struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev); struct qrtr_smd_dev *qdev = qcom_smd_get_drvdata(channel);
int rc; int rc;
if (!qdev) if (!qdev)
...@@ -35,7 +36,7 @@ static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev, ...@@ -35,7 +36,7 @@ static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev,
rc = qrtr_endpoint_post(&qdev->ep, data, len); rc = qrtr_endpoint_post(&qdev->ep, data, len);
if (rc == -EINVAL) { if (rc == -EINVAL) {
dev_err(&sdev->dev, "invalid ipcrouter packet\n"); dev_err(qdev->dev, "invalid ipcrouter packet\n");
/* return 0 to let smd drop the packet */ /* return 0 to let smd drop the packet */
rc = 0; rc = 0;
} }
...@@ -73,12 +74,14 @@ static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev) ...@@ -73,12 +74,14 @@ static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev)
return -ENOMEM; return -ENOMEM;
qdev->channel = sdev->channel; qdev->channel = sdev->channel;
qdev->dev = &sdev->dev;
qdev->ep.xmit = qcom_smd_qrtr_send; qdev->ep.xmit = qcom_smd_qrtr_send;
rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
if (rc) if (rc)
return rc; return rc;
qcom_smd_set_drvdata(sdev->channel, qdev);
dev_set_drvdata(&sdev->dev, qdev); dev_set_drvdata(&sdev->dev, qdev);
dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n"); dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册