Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f79a917e authored by Bjorn Andersson's avatar Bjorn Andersson
Browse files

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.

Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parents ed7cbbce b853cb96
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1470,7 +1470,10 @@ F: arch/arm/boot/dts/qcom-*.dts
F:	arch/arm/boot/dts/qcom-*.dtsi
F:	arch/arm/mach-qcom/
F:	arch/arm64/boot/dts/qcom/*
F:	drivers/i2c/busses/i2c-qup.c
F:	drivers/clk/qcom/
F:	drivers/soc/qcom/
F:	drivers/spi/spi-qup.c
F:	drivers/tty/serial/msm_serial.h
F:	drivers/tty/serial/msm_serial.c
F:	drivers/*/pm8???-*
+6 −3
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
 */
struct qcom_smd_rpm {
	struct qcom_smd_channel *rpm_channel;
	struct device *dev;

	struct completion ack;
	struct mutex lock;
@@ -149,14 +150,14 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
}
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,
				 size_t count)
{
	const struct qcom_rpm_header *hdr = data;
	size_t hdr_length = le32_to_cpu(hdr->length);
	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 *end = buf + hdr_length;
	char msgbuf[32];
@@ -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 ||
	    hdr_length < sizeof(struct qcom_rpm_message)) {
		dev_err(&qsdev->dev, "invalid request\n");
		dev_err(rpm->dev, "invalid request\n");
		return 0;
	}

@@ -206,7 +207,9 @@ static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev)
	mutex_init(&rpm->lock);
	init_completion(&rpm->ack);

	rpm->dev = &sdev->dev;
	rpm->rpm_channel = sdev->channel;
	qcom_smd_set_drvdata(sdev->channel, rpm);

	dev_set_drvdata(&sdev->dev, rpm);

+188 −59
Original line number Diff line number Diff line
@@ -106,9 +106,9 @@ static const struct {
 * @channels:		list of all channels detected on this edge
 * @channels_lock:	guard for modifications of @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
 * @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 *smd;
@@ -127,10 +127,12 @@ struct qcom_smd_edge {

	DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);

	bool need_rescan;
	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 {
	int fifo_size;

	void *bounce_buffer;
	int (*cb)(struct qcom_smd_device *, const void *, size_t);
	qcom_smd_cb_t cb;

	spinlock_t recv_lock;

	int pkt_size;

	void *drvdata;

	struct list_head list;
	struct list_head dev_list;
};

/**
@@ -377,6 +382,19 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
	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
 */
@@ -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)
{
	struct qcom_smd_device *qsdev = channel->qsdev;
	unsigned tail;
	size_t len;
	void *ptr;
@@ -517,7 +534,7 @@ static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
		len = channel->pkt_size;
	}

	ret = channel->cb(qsdev, ptr, len);
	ret = channel->cb(channel, ptr, len);
	if (ret < 0)
		return ret;

@@ -601,7 +618,8 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
	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
@@ -609,7 +627,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
	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);
	}
	spin_unlock(&edge->channels_lock);
@@ -622,12 +640,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
	available = qcom_smem_get_free_space(edge->remote_pid);
	if (available != edge->smem_available) {
		edge->smem_available = available;
		edge->need_rescan = true;
		kick_worker = true;
		kick_scanner = true;
	}

	if (kick_worker)
		schedule_work(&edge->work);
	if (kick_scanner)
		schedule_work(&edge->scan_work);
	if (kick_state)
		schedule_work(&edge->state_work);

	return IRQ_HANDLED;
}
@@ -793,18 +812,12 @@ static int qcom_smd_dev_match(struct device *dev, struct device_driver *drv)
}

/*
 * 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.
 * Helper for opening a channel
 */
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;
	int ret;

	/*
	 * Packets are maximum 4k, but reduce if the fifo is smaller
@@ -814,12 +827,44 @@ static int qcom_smd_dev_probe(struct device *dev)
	if (!channel->bounce_buffer)
		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_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);
	if (ret)
		goto err;
@@ -831,11 +876,7 @@ static int qcom_smd_dev_probe(struct device *dev)
err:
	dev_err(&qsdev->dev, "probe failed\n");

	channel->cb = NULL;
	kfree(channel->bounce_buffer);
	channel->bounce_buffer = NULL;

	qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);
	qcom_smd_channel_close(channel);
	return ret;
}

@@ -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_driver *qsdrv = to_smd_driver(dev);
	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);

	/*
	 * Make sure we don't race with the code receiving data.
	 */
	spin_lock_irqsave(&channel->recv_lock, flags);
	channel->cb = NULL;
	spin_unlock_irqrestore(&channel->recv_lock, flags);
	qcom_smd_channel_set_callback(channel, NULL);

	/* Wake up any sleepers in qcom_smd_send() */
	wake_up_interruptible(&channel->fblockread_event);
@@ -872,15 +912,14 @@ static int qcom_smd_dev_remove(struct device *dev)
		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;
	kfree(channel->bounce_buffer);
	channel->bounce_buffer = NULL;

	qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED);

	qcom_smd_channel_reset(channel);
	list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) {
		qcom_smd_channel_close(ch);
		list_del(&ch->dev_list);
		ch->qsdev = NULL;
	}

	return 0;
}
@@ -996,6 +1035,18 @@ int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv)
}
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
 * @qsdrv:	qcom_smd_driver struct
@@ -1006,6 +1057,78 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv)
}
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,
 * 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
	if (!channel)
		return ERR_PTR(-ENOMEM);

	INIT_LIST_HEAD(&channel->dev_list);
	channel->edge = edge;
	channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL);
	if (!channel->name)
@@ -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
 * 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 *entry;
	struct qcom_smd_channel *channel;
@@ -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);
			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)
 * then scans all registered channels for state changes that should be handled
 * by creating or destroying smd client devices for the registered channels.
 *
 * LOCKING: edge->channels_lock is not needed to be held during the traversal
 * of the channels list as it's done synchronously with the only writer.
 * LOCKING: edge->channels_lock only needs to cover the list operations, as the
 * worker is killed before any channels are deallocated
 */
static void qcom_channel_state_worker(struct work_struct *work)
{
	struct qcom_smd_channel *channel;
	struct qcom_smd_edge *edge = container_of(work,
						  struct qcom_smd_edge,
						  work);
						  state_work);
	unsigned remote_state;

	/*
	 * 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);
	}
	unsigned long flags;

	/*
	 * Register a device for any closed channel where the remote processor
	 * is showing interest in opening the channel.
	 */
	spin_lock_irqsave(&edge->channels_lock, flags);
	list_for_each_entry(channel, &edge->channels, list) {
		if (channel->state != SMD_CHANNEL_CLOSED)
			continue;
@@ -1183,7 +1304,9 @@ static void qcom_channel_state_worker(struct work_struct *work)
		    remote_state != SMD_CHANNEL_OPENED)
			continue;

		spin_unlock_irqrestore(&edge->channels_lock, flags);
		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)
		    remote_state == SMD_CHANNEL_OPENED)
			continue;

		spin_unlock_irqrestore(&edge->channels_lock, flags);
		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,
	INIT_LIST_HEAD(&edge->channels);
	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);

@@ -1303,13 +1430,13 @@ static int qcom_smd_probe(struct platform_device *pdev)
	for_each_available_child_of_node(pdev->dev.of_node, node) {
		edge = &smd->edges[i++];
		edge->smd = smd;
		init_waitqueue_head(&edge->new_channel_event);

		ret = qcom_smd_parse_edge(&pdev->dev, node, edge);
		if (ret)
			continue;

		edge->need_rescan = true;
		schedule_work(&edge->work);
		schedule_work(&edge->scan_work);
	}

	platform_set_drvdata(pdev, smd);
@@ -1332,8 +1459,10 @@ static int qcom_smd_remove(struct platform_device *pdev)
		edge = &smd->edges[i];

		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) {
			if (!channel->qsdev)
				continue;
+1 −2
Original line number Diff line number Diff line
@@ -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].size = resource_size(&r);
	smem->regions[i].virt_base = devm_ioremap_nocache(dev, r.start,
							  resource_size(&r));
	smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
	if (!smem->regions[i].virt_base)
		return -ENOMEM;

+3 −5
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
 * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014,2015, Linaro Ltd.
 *
 * SAW power controller driver
 *
 * 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
 * only version 2 as published by the Free Software Foundation.
@@ -12,7 +14,6 @@
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -378,8 +379,5 @@ static struct platform_driver spm_driver = {
		.of_match_table = spm_match_table,
	},
};
module_platform_driver(spm_driver);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SAW power controller driver");
MODULE_ALIAS("platform:saw");
builtin_platform_driver(spm_driver);
Loading