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

Commit 74465b4f authored by Dan Williams's avatar Dan Williams
Browse files

atmel-mci: convert to dma_request_channel and down-level dma_slave



dma_request_channel provides an exclusive channel, so we no longer need to
pass slave data through dmaengine.

Cc: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 33df8ca0
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@

#define ATMEL_MCI_MAX_NR_SLOTS	2

struct dma_slave;
#include <linux/dw_dmac.h>

/**
 * struct mci_slot_pdata - board-specific per-slot configuration
@@ -28,11 +28,11 @@ struct mci_slot_pdata {

/**
 * struct mci_platform_data - board-specific MMC/SDcard configuration
 * @dma_slave: DMA slave interface to use in data transfers, or NULL.
 * @dma_slave: DMA slave interface to use in data transfers.
 * @slot: Per-slot configuration data.
 */
struct mci_platform_data {
	struct dma_slave	*dma_slave;
	struct dw_dma_slave	dma_slave;
	struct mci_slot_pdata	slot[ATMEL_MCI_MAX_NR_SLOTS];
};

+3 −12
Original line number Diff line number Diff line
@@ -1305,7 +1305,7 @@ struct platform_device *__init
at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
{
	struct platform_device		*pdev;
	struct dw_dma_slave		*dws;
	struct dw_dma_slave		*dws = &data->dma_slave;
	u32				pioa_mask;
	u32				piob_mask;

@@ -1324,22 +1324,13 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
				ARRAY_SIZE(atmel_mci0_resource)))
		goto fail;

	if (data->dma_slave)
		dws = kmemdup(to_dw_dma_slave(data->dma_slave),
				sizeof(struct dw_dma_slave), GFP_KERNEL);
	else
		dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);

	dws->slave.dev = &pdev->dev;
	dws->slave.dma_dev = &dw_dmac0_device.dev;
	dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
	dws->dma_dev = &dw_dmac0_device.dev;
	dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
	dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
				| DWC_CFGH_DST_PER(1));
	dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
				| DWC_CFGL_HS_SRC_POL);

	data->dma_slave = &dws->slave;

	if (platform_device_add_data(pdev, data,
				sizeof(struct mci_platform_data)))
		goto fail;
+0 −8
Original line number Diff line number Diff line
@@ -234,10 +234,6 @@ static void dma_client_chan_alloc(struct dma_client *client)
	list_for_each_entry(device, &dma_device_list, global_node) {
		if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
			continue;
		/* Does the client require a specific DMA controller? */
		if (client->slave && client->slave->dma_dev
				&& client->slave->dma_dev != device->dev)
			continue;
		if (!dma_device_satisfies_mask(device, client->cap_mask))
			continue;

@@ -613,10 +609,6 @@ void dma_async_client_register(struct dma_client *client)
	struct dma_chan *chan;
	int err;

	/* validate client data */
	BUG_ON(dma_has_cap(DMA_SLAVE, client->cap_mask) &&
		!client->slave);

	mutex_lock(&dma_list_mutex);
	dmaengine_ref_count++;

+6 −19
Original line number Diff line number Diff line
@@ -567,7 +567,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
	if (unlikely(!dws || !sg_len))
		return NULL;

	reg_width = dws->slave.reg_width;
	reg_width = dws->reg_width;
	prev = first = NULL;

	sg_len = dma_map_sg(chan->dev.parent, sgl, sg_len, direction);
@@ -579,7 +579,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
				| DWC_CTLL_DST_FIX
				| DWC_CTLL_SRC_INC
				| DWC_CTLL_FC_M2P);
		reg = dws->slave.tx_reg;
		reg = dws->tx_reg;
		for_each_sg(sgl, sg, sg_len, i) {
			struct dw_desc	*desc;
			u32		len;
@@ -625,7 +625,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
				| DWC_CTLL_SRC_FIX
				| DWC_CTLL_FC_P2M);

		reg = dws->slave.rx_reg;
		reg = dws->rx_reg;
		for_each_sg(sgl, sg, sg_len, i) {
			struct dw_desc	*desc;
			u32		len;
@@ -764,7 +764,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
	struct dw_dma		*dw = to_dw_dma(chan->device);
	struct dw_desc		*desc;
	struct dma_slave	*slave;
	struct dw_dma_slave	*dws;
	int			i;
	u32			cfghi;
@@ -772,12 +771,6 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,

	dev_vdbg(&chan->dev, "alloc_chan_resources\n");

	/* Channels doing slave DMA can only handle one client. */
	if (dwc->dws || (client && client->slave)) {
		if (chan->client_count)
			return -EBUSY;
	}

	/* ASSERT:  channel is idle */
	if (dma_readl(dw, CH_EN) & dwc->mask) {
		dev_dbg(&chan->dev, "DMA channel not idle?\n");
@@ -789,23 +782,17 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
	cfghi = DWC_CFGH_FIFO_MODE;
	cfglo = 0;

	slave = client->slave;
	if (slave) {
	dws = dwc->dws;
	if (dws) {
		/*
		 * We need controller-specific data to set up slave
		 * transfers.
		 */
		BUG_ON(!slave->dma_dev || slave->dma_dev != dw->dma.dev);

		dws = container_of(slave, struct dw_dma_slave, slave);
		BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);

		dwc->dws = dws;
		cfghi = dws->cfg_hi;
		cfglo = dws->cfg_lo;
	} else {
		dwc->dws = NULL;
	}

	channel_writel(dwc, CFG_LO, cfglo);
	channel_writel(dwc, CFG_HI, cfghi);

+27 −71
Original line number Diff line number Diff line
@@ -1441,60 +1441,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
	return IRQ_HANDLED;
}

#ifdef CONFIG_MMC_ATMELMCI_DMA

static inline struct atmel_mci *
dma_client_to_atmel_mci(struct dma_client *client)
{
	return container_of(client, struct atmel_mci, dma.client);
}

static enum dma_state_client atmci_dma_event(struct dma_client *client,
		struct dma_chan *chan, enum dma_state state)
{
	struct atmel_mci	*host;
	enum dma_state_client	ret = DMA_NAK;

	host = dma_client_to_atmel_mci(client);

	switch (state) {
	case DMA_RESOURCE_AVAILABLE:
		spin_lock_bh(&host->lock);
		if (!host->dma.chan) {
			host->dma.chan = chan;
			ret = DMA_ACK;
		}
		spin_unlock_bh(&host->lock);

		if (ret == DMA_ACK)
			dev_info(&host->pdev->dev,
					"Using %s for DMA transfers\n",
					chan->dev.bus_id);
		break;

	case DMA_RESOURCE_REMOVED:
		spin_lock_bh(&host->lock);
		if (host->dma.chan == chan) {
			host->dma.chan = NULL;
			ret = DMA_ACK;
		}
		spin_unlock_bh(&host->lock);

		if (ret == DMA_ACK)
			dev_info(&host->pdev->dev,
					"Lost %s, falling back to PIO\n",
					chan->dev.bus_id);
		break;

	default:
		break;
	}


	return ret;
}
#endif /* CONFIG_MMC_ATMELMCI_DMA */

static int __init atmci_init_slot(struct atmel_mci *host,
		struct mci_slot_pdata *slot_data, unsigned int id,
		u32 sdc_reg)
@@ -1598,6 +1544,18 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
	mmc_free_host(slot->mmc);
}

#ifdef CONFIG_MMC_ATMELMCI_DMA
static enum dma_state_client filter(struct dma_chan *chan, void *slave)
{
	struct dw_dma_slave *dws = slave;

	if (dws->dma_dev == chan->device->dev)
		return DMA_ACK;
	else
		return DMA_DUP;
}
#endif

static int __init atmci_probe(struct platform_device *pdev)
{
	struct mci_platform_data	*pdata;
@@ -1650,22 +1608,20 @@ static int __init atmci_probe(struct platform_device *pdev)
		goto err_request_irq;

#ifdef CONFIG_MMC_ATMELMCI_DMA
	if (pdata->dma_slave) {
		struct dma_slave *slave = pdata->dma_slave;
	if (pdata->dma_slave.dma_dev) {
		struct dw_dma_slave *dws = &pdata->dma_slave;
		dma_cap_mask_t mask;

		slave->tx_reg = regs->start + MCI_TDR;
		slave->rx_reg = regs->start + MCI_RDR;
		dws->tx_reg = regs->start + MCI_TDR;
		dws->rx_reg = regs->start + MCI_RDR;

		/* Try to grab a DMA channel */
		host->dma.client.event_callback = atmci_dma_event;
		dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
		host->dma.client.slave = slave;

		dma_async_client_register(&host->dma.client);
		dma_async_client_chan_request(&host->dma.client);
	} else {
		dev_notice(&pdev->dev, "DMA not available, using PIO\n");
		dma_cap_zero(mask);
		dma_cap_set(DMA_SLAVE, mask);
		host->dma.chan = dma_request_channel(mask, filter, dws);
	}
	if (!host->dma.chan)
		dev_notice(&pdev->dev, "DMA not available, using PIO\n");
#endif /* CONFIG_MMC_ATMELMCI_DMA */

	platform_set_drvdata(pdev, host);
@@ -1697,8 +1653,8 @@ static int __init atmci_probe(struct platform_device *pdev)

err_init_slot:
#ifdef CONFIG_MMC_ATMELMCI_DMA
	if (pdata->dma_slave)
		dma_async_client_unregister(&host->dma.client);
	if (host->dma.chan)
		dma_release_channel(host->dma.chan);
#endif
	free_irq(irq, host);
err_request_irq:
@@ -1729,8 +1685,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
	clk_disable(host->mck);

#ifdef CONFIG_MMC_ATMELMCI_DMA
	if (host->dma.client.slave)
		dma_async_client_unregister(&host->dma.client);
	if (host->dma.chan)
		dma_release_channel(host->dma.chan);
#endif

	free_irq(platform_get_irq(pdev, 0), host);
@@ -1759,7 +1715,7 @@ static void __exit atmci_exit(void)
	platform_driver_unregister(&atmci_driver);
}

module_init(atmci_init);
late_initcall(atmci_init); /* try to load after dma driver when built-in */
module_exit(atmci_exit);

MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
Loading