Loading MAINTAINERS +3 −0 Original line number Diff line number Diff line Loading @@ -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???-* Loading drivers/soc/qcom/smd-rpm.c +6 −3 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ */ struct qcom_smd_rpm { struct qcom_smd_channel *rpm_channel; struct device *dev; struct completion ack; struct mutex lock; Loading Loading @@ -149,14 +150,14 @@ out: } 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]; Loading @@ -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; } Loading Loading @@ -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); Loading drivers/soc/qcom/smd.c +188 −59 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; }; /* Loading Loading @@ -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; }; /** Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 Loading @@ -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; Loading @@ -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; } Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 Loading @@ -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. Loading @@ -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) Loading Loading @@ -1089,8 +1213,9 @@ free_name_and_channel: * 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; Loading Loading @@ -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); } /* Loading @@ -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; Loading @@ -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); } /* Loading @@ -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); } /* Loading @@ -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); Loading Loading @@ -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); Loading @@ -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; Loading drivers/soc/qcom/smem.c +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading drivers/soc/qcom/spm.c +3 −5 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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> Loading Loading @@ -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
MAINTAINERS +3 −0 Original line number Diff line number Diff line Loading @@ -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???-* Loading
drivers/soc/qcom/smd-rpm.c +6 −3 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ */ struct qcom_smd_rpm { struct qcom_smd_channel *rpm_channel; struct device *dev; struct completion ack; struct mutex lock; Loading Loading @@ -149,14 +150,14 @@ out: } 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]; Loading @@ -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; } Loading Loading @@ -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); Loading
drivers/soc/qcom/smd.c +188 −59 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; }; /* Loading Loading @@ -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; }; /** Loading Loading @@ -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 */ Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 Loading @@ -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; Loading @@ -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; } Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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 Loading @@ -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. Loading @@ -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) Loading Loading @@ -1089,8 +1213,9 @@ free_name_and_channel: * 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; Loading Loading @@ -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); } /* Loading @@ -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; Loading @@ -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); } /* Loading @@ -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); } /* Loading @@ -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); Loading Loading @@ -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); Loading @@ -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; Loading
drivers/soc/qcom/smem.c +1 −2 Original line number Diff line number Diff line Loading @@ -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; Loading
drivers/soc/qcom/spm.c +3 −5 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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> Loading Loading @@ -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);