cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i2c-stm32.c (3831B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * i2c-stm32.c
      4 *
      5 * Copyright (C) M'boumba Cedric Madianga 2017
      6 * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
      7 */
      8
      9#include "i2c-stm32.h"
     10
     11/* Functions for DMA support */
     12struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
     13					    dma_addr_t phy_addr,
     14					    u32 txdr_offset,
     15					    u32 rxdr_offset)
     16{
     17	struct stm32_i2c_dma *dma;
     18	struct dma_slave_config dma_sconfig;
     19	int ret;
     20
     21	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
     22	if (!dma)
     23		return ERR_PTR(-ENOMEM);
     24
     25	/* Request and configure I2C TX dma channel */
     26	dma->chan_tx = dma_request_chan(dev, "tx");
     27	if (IS_ERR(dma->chan_tx)) {
     28		ret = PTR_ERR(dma->chan_tx);
     29		if (ret != -ENODEV)
     30			ret = dev_err_probe(dev, ret,
     31					    "can't request DMA tx channel\n");
     32		goto fail_al;
     33	}
     34
     35	memset(&dma_sconfig, 0, sizeof(dma_sconfig));
     36	dma_sconfig.dst_addr = phy_addr + txdr_offset;
     37	dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
     38	dma_sconfig.dst_maxburst = 1;
     39	dma_sconfig.direction = DMA_MEM_TO_DEV;
     40	ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
     41	if (ret < 0) {
     42		dev_err(dev, "can't configure tx channel\n");
     43		goto fail_tx;
     44	}
     45
     46	/* Request and configure I2C RX dma channel */
     47	dma->chan_rx = dma_request_chan(dev, "rx");
     48	if (IS_ERR(dma->chan_rx)) {
     49		ret = PTR_ERR(dma->chan_rx);
     50		if (ret != -ENODEV)
     51			ret = dev_err_probe(dev, ret,
     52					    "can't request DMA rx channel\n");
     53
     54		goto fail_tx;
     55	}
     56
     57	memset(&dma_sconfig, 0, sizeof(dma_sconfig));
     58	dma_sconfig.src_addr = phy_addr + rxdr_offset;
     59	dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
     60	dma_sconfig.src_maxburst = 1;
     61	dma_sconfig.direction = DMA_DEV_TO_MEM;
     62	ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
     63	if (ret < 0) {
     64		dev_err(dev, "can't configure rx channel\n");
     65		goto fail_rx;
     66	}
     67
     68	init_completion(&dma->dma_complete);
     69
     70	dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
     71		 dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
     72
     73	return dma;
     74
     75fail_rx:
     76	dma_release_channel(dma->chan_rx);
     77fail_tx:
     78	dma_release_channel(dma->chan_tx);
     79fail_al:
     80	devm_kfree(dev, dma);
     81
     82	return ERR_PTR(ret);
     83}
     84
     85void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
     86{
     87	dma->dma_buf = 0;
     88	dma->dma_len = 0;
     89
     90	dma_release_channel(dma->chan_tx);
     91	dma->chan_tx = NULL;
     92
     93	dma_release_channel(dma->chan_rx);
     94	dma->chan_rx = NULL;
     95
     96	dma->chan_using = NULL;
     97}
     98
     99int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma,
    100			    bool rd_wr, u32 len, u8 *buf,
    101			    dma_async_tx_callback callback,
    102			    void *dma_async_param)
    103{
    104	struct dma_async_tx_descriptor *txdesc;
    105	struct device *chan_dev;
    106	int ret;
    107
    108	if (rd_wr) {
    109		dma->chan_using = dma->chan_rx;
    110		dma->dma_transfer_dir = DMA_DEV_TO_MEM;
    111		dma->dma_data_dir = DMA_FROM_DEVICE;
    112	} else {
    113		dma->chan_using = dma->chan_tx;
    114		dma->dma_transfer_dir = DMA_MEM_TO_DEV;
    115		dma->dma_data_dir = DMA_TO_DEVICE;
    116	}
    117
    118	dma->dma_len = len;
    119	chan_dev = dma->chan_using->device->dev;
    120
    121	dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len,
    122				      dma->dma_data_dir);
    123	if (dma_mapping_error(chan_dev, dma->dma_buf)) {
    124		dev_err(dev, "DMA mapping failed\n");
    125		return -EINVAL;
    126	}
    127
    128	txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf,
    129					     dma->dma_len,
    130					     dma->dma_transfer_dir,
    131					     DMA_PREP_INTERRUPT);
    132	if (!txdesc) {
    133		dev_err(dev, "Not able to get desc for DMA xfer\n");
    134		ret = -EINVAL;
    135		goto err;
    136	}
    137
    138	reinit_completion(&dma->dma_complete);
    139
    140	txdesc->callback = callback;
    141	txdesc->callback_param = dma_async_param;
    142	ret = dma_submit_error(dmaengine_submit(txdesc));
    143	if (ret < 0) {
    144		dev_err(dev, "DMA submit failed\n");
    145		goto err;
    146	}
    147
    148	dma_async_issue_pending(dma->chan_using);
    149
    150	return 0;
    151
    152err:
    153	dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len,
    154			 dma->dma_data_dir);
    155	return ret;
    156}