@@ -257,7 +257,8 @@ struct scpi_xfer {
struct scpi_chan {
struct mbox_client cl;
- struct mbox_chan *chan;
+ struct mbox_chan *tx_chan;
+ struct mbox_chan *rx_chan;
void __iomem *tx_payload;
void __iomem *rx_payload;
struct list_head rx_pending;
@@ -541,7 +542,7 @@
msg->rx_len = rx_len;
reinit_completion(&msg->done);
- ret = mbox_send_message(scpi_chan->chan, msg);
+ ret = mbox_send_message(scpi_chan->tx_chan, msg);
if (ret < 0 || !rx_buf)
goto out;
@@ -894,8 +895,10 @@
{
int i;
- for (i = 0; i < count && pchan->chan; i++, pchan++) {
- mbox_free_channel(pchan->chan);
+ for (i = 0; i < count && pchan->tx_chan; i++, pchan++) {
+ if (pchan->rx_chan && pchan->rx_chan != pchan->tx_chan)
+ mbox_free_channel(pchan->rx_chan);
+ mbox_free_channel(pchan->tx_chan);
devm_kfree(dev, pchan->xfers);
devm_iounmap(dev, pchan->rx_payload);
}
@@ -968,6 +971,7 @@
dev_err(dev, "no mboxes property in '%pOF'\n", np);
return -ENODEV;
}
+ count /= 2;
scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL);
if (!scpi_chan)
@@ -1009,13 +1013,19 @@
ret = scpi_alloc_xfer_list(dev, pchan);
if (!ret) {
- pchan->chan = mbox_request_channel(cl, idx);
- if (!IS_ERR(pchan->chan))
+ pchan->tx_chan = mbox_request_channel(cl, idx * 2);
+ pchan->rx_chan = mbox_request_channel(cl, idx * 2 + 1);
+ /* This isn't quite right, but the idea stands. */
+ if (!IS_ERR(pchan->tx_chan) && !IS_ERR(pchan->rx_chan))
continue;
- ret = PTR_ERR(pchan->chan);
+ ret = PTR_ERR(pchan->tx_chan);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get channel%d err %d\n",
- idx, ret);
+ idx * 2, ret);
+ ret = PTR_ERR(pchan->rx_chan);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get channel%d err %d\n",
+ idx * 2 + 1, ret);
}
err:
scpi_free_channels(dev, scpi_chan, idx);
But then there are two copies of almost exactly the same driver! If there was an
API for determining if a channel was unidirectional or bidirectional, than it
would be trivial to support both models in one driver:
@@ -953,7 +955,7 @@
static int scpi_probe(struct platform_device *pdev)
{
- int count, idx, ret;
+ int count, idx, mbox_idx, ret;
struct resource res;
struct scpi_chan *scpi_chan;
struct device *dev = &pdev->dev;
@@ -971,13 +973,12 @@
dev_err(dev, "no mboxes property in '%pOF'\n", np);
return -ENODEV;
}
- count /= 2;
scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL);
if (!scpi_chan)
return -ENOMEM;
- for (idx = 0; idx < count; idx++) {
+ for (idx = 0, mbox_idx = 0; mbox_idx < count; idx++) {
resource_size_t size;
struct scpi_chan *pchan = scpi_chan + idx;
struct mbox_client *cl = &pchan->cl;
@@ -1014,7 +1015,13 @@
ret = scpi_alloc_xfer_list(dev, pchan);
if (!ret) {
pchan->tx_chan = mbox_request_channel(cl, idx * 2);
- pchan->rx_chan = mbox_request_channel(cl, idx * 2 + 1);
+ if (mbox_chan_is_bidirectional(pchan->tx_chan)) {
+ pchan->rx_chan = pchan->tx_chan;
+ mbox_idx += 1;
+ } else {
+ pchan->rx_chan = mbox_request_channel(cl, idx * 2 + 1);
+ mbox_idx += 2;
+ }
/* This isn't quite right, but the idea stands. */
if (!IS_ERR(pchan->tx_chan) && !IS_ERR(pchan->rx_chan))
continue;
@@ -1034,7 +1041,7 @@
}
scpi_info->channels = scpi_chan;
- scpi_info->num_chans = count;
+ scpi_info->num_chans = idx;
scpi_info->commands = scpi_std_commands;
platform_set_drvdata(pdev, scpi_info);