On 08/30/2013 04:19 AM, Rajendra Nayak wrote: > [].. > >> + >> +#define pr_fmt(fmt) "%s: " fmt, __func__ >> + >> +#ifdef DEBUG >> +#define prn(num) printk(#num "=%d\n", num) >> +#define prx(num) printk(#num "=%x\n", num) >> +#else >> +#define prn(num) do { } while (0) >> +#define prx(num) do { } while (0) >> +#endif >> + >> +#include <linux/err.h> >> +#include <linux/module.h> >> +#include <linux/init.h> >> +#include <linux/errno.h> >> +#include <linux/kernel.h> >> +#include <linux/platform_device.h> >> +#include <linux/scatterlist.h> >> +#include <linux/dma-mapping.h> >> +#include <linux/dmaengine.h> >> +#include <linux/omap-dma.h> >> +#include <linux/pm_runtime.h> >> +#include <linux/of.h> >> +#include <linux/of_device.h> >> +#include <linux/of_address.h> >> +#include <linux/io.h> >> +#include <linux/crypto.h> >> +#include <linux/interrupt.h> >> +#include <crypto/scatterwalk.h> >> +#include <crypto/des.h> >> + >> +#define DST_MAXBURST 2 >> + >> +#define DES_BLOCK_WORDS (DES_BLOCK_SIZE >> 2) >> + >> +#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset) >> + >> +#define DES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \ >> + ((x ^ 0x01) * 0x04)) >> + >> +#define DES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) >> + >> +#define DES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) >> +#define DES_REG_CTRL_CBC (1 << 4) >> +#define DES_REG_CTRL_TDES (1 << 3) >> +#define DES_REG_CTRL_DIRECTION (1 << 2) >> +#define DES_REG_CTRL_INPUT_READY (1 << 1) >> +#define DES_REG_CTRL_OUTPUT_READY (1 << 0) > > Why not use bitops like you have done below. Ok, will do that. > >> + >> +#define DES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) >> + >> +#define DES_REG_REV(dd) ((dd)->pdata->rev_ofs) >> + >> +#define DES_REG_MASK(dd) ((dd)->pdata->mask_ofs) >> + >> +#define DES_REG_LENGTH_N(x) (0x24 + ((x) * 0x04)) >> + >> +#define DES_REG_IRQ_STATUS(dd) ((dd)->pdata->irq_status_ofs) >> +#define DES_REG_IRQ_ENABLE(dd) ((dd)->pdata->irq_enable_ofs) >> +#define DES_REG_IRQ_DATA_IN BIT(1) >> +#define DES_REG_IRQ_DATA_OUT BIT(2) >> + >> +#define FLAGS_MODE_MASK 0x000f >> +#define FLAGS_ENCRYPT BIT(0) >> +#define FLAGS_CBC BIT(1) >> +#define FLAGS_INIT BIT(4) >> +#define FLAGS_BUSY BIT(6) >> + > > [].. > >> +struct omap_des_pdata { >> + struct omap_des_algs_info *algs_info; >> + unsigned int algs_info_size; >> + >> + void (*trigger)(struct omap_des_dev *dd, int length); > > Is this really used? How does a DT platform pass function pointers? This is hard coded in the pdata structures for each platform and provided once the DT matches. Different platforms may have different pdata. >> + >> + u32 key_ofs; >> + u32 iv_ofs; >> + u32 ctrl_ofs; >> + u32 data_ofs; >> + u32 rev_ofs; >> + u32 mask_ofs; >> + u32 irq_enable_ofs; >> + u32 irq_status_ofs; >> + >> + u32 dma_enable_in; >> + u32 dma_enable_out; >> + u32 dma_start; >> + >> + u32 major_mask; >> + u32 major_shift; >> + u32 minor_mask; >> + u32 minor_shift; >> +}; >> + >> +struct omap_des_dev { >> + struct list_head list; >> + unsigned long phys_base; >> + void __iomem *io_base; >> + struct omap_des_ctx *ctx; >> + struct device *dev; >> + unsigned long flags; >> + int err; >> + >> + /* spinlock used for queues */ >> + spinlock_t lock; >> + struct crypto_queue queue; >> + >> + struct tasklet_struct done_task; >> + struct tasklet_struct queue_task; >> + >> + struct ablkcipher_request *req; >> + /* >> + * total is used by PIO mode for book keeping so introduce >> + * variable total_save as need it to calc page_order >> + */ >> + size_t total; >> + size_t total_save; >> + >> + struct scatterlist *in_sg; >> + struct scatterlist *out_sg; >> + >> + /* Buffers for copying for unaligned cases */ >> + struct scatterlist in_sgl; >> + struct scatterlist out_sgl; >> + struct scatterlist *orig_out; >> + int sgs_copied; >> + >> + struct scatter_walk in_walk; >> + struct scatter_walk out_walk; >> + int dma_in; >> + struct dma_chan *dma_lch_in; >> + int dma_out; >> + struct dma_chan *dma_lch_out; >> + int in_sg_len; >> + int out_sg_len; >> + int pio_only; >> + const struct omap_des_pdata *pdata; >> +}; >> + >> +/* keep registered devices data here */ >> +static LIST_HEAD(dev_list); >> +static DEFINE_SPINLOCK(list_lock); >> + > > [].. > >> + >> +static int omap_des_crypt_dma_start(struct omap_des_dev *dd) >> +{ >> + struct crypto_tfm *tfm = crypto_ablkcipher_tfm( >> + crypto_ablkcipher_reqtfm(dd->req)); >> + int err; >> + >> + pr_debug("total: %d\n", dd->total); >> + >> + if (!dd->pio_only) { >> + err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len, >> + DMA_TO_DEVICE); >> + if (!err) { >> + dev_err(dd->dev, "dma_map_sg() error\n"); >> + return -EINVAL; >> + } >> + >> + err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len, >> + DMA_FROM_DEVICE); >> + if (!err) { >> + dev_err(dd->dev, "dma_map_sg() error\n"); >> + return -EINVAL; >> + } >> + } >> + >> + err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len, >> + dd->out_sg_len); >> + if (err && !dd->pio_only) { >> + dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); >> + dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, >> + DMA_FROM_DEVICE); >> + } >> + >> + return err; >> +} >> + >> +static void omap_des_finish_req(struct omap_des_dev *dd, int err) >> +{ >> + struct ablkcipher_request *req = dd->req; >> + >> + pr_debug("err: %d\n", err); >> + >> + pm_runtime_put(dd->dev); > > You seem to do a pm_runtime_get_sync() in omap_des_write_ctrl() and a > pm_runtime_put() here and not a pm_runtime_put_sync()? Yes, that's on purpose :) I had submitted a fix earlier to do that. http://www.spinics.net/lists/linux-crypto/msg08482.html > >> + >> +#ifdef CONFIG_OF >> +static const struct omap_des_pdata omap_des_pdata_omap4 = { >> + .algs_info = omap_des_algs_info_ecb_cbc, >> + .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc), >> + .trigger = omap_des_dma_trigger_omap4, >> + .key_ofs = 0x14, >> + .iv_ofs = 0x18, >> + .ctrl_ofs = 0x20, >> + .data_ofs = 0x28, >> + .rev_ofs = 0x30, >> + .mask_ofs = 0x34, >> + .irq_status_ofs = 0x3c, >> + .irq_enable_ofs = 0x40, >> + .dma_enable_in = BIT(5), >> + .dma_enable_out = BIT(6), >> + .major_mask = 0x0700, >> + .major_shift = 8, >> + .minor_mask = 0x003f, >> + .minor_shift = 0, >> +}; >> + >> +static irqreturn_t omap_des_irq(int irq, void *dev_id) >> +{ >> + struct omap_des_dev *dd = dev_id; >> + u32 status, i; >> + u32 *src, *dst; >> + >> + status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd)); >> + if (status & DES_REG_IRQ_DATA_IN) { >> + omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); >> + >> + BUG_ON(!dd->in_sg); >> + >> + BUG_ON(_calc_walked(in) > dd->in_sg->length); >> + >> + src = sg_virt(dd->in_sg) + _calc_walked(in); >> + >> + for (i = 0; i < DES_BLOCK_WORDS; i++) { >> + omap_des_write(dd, DES_REG_DATA_N(dd, i), *src); >> + >> + scatterwalk_advance(&dd->in_walk, 4); >> + if (dd->in_sg->length == _calc_walked(in)) { >> + dd->in_sg = scatterwalk_sg_next(dd->in_sg); >> + if (dd->in_sg) { >> + scatterwalk_start(&dd->in_walk, >> + dd->in_sg); >> + src = sg_virt(dd->in_sg) + >> + _calc_walked(in); >> + } >> + } else { >> + src++; >> + } >> + } >> + >> + /* Clear IRQ status */ >> + status &= ~DES_REG_IRQ_DATA_IN; >> + omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); >> + >> + /* Enable DATA_OUT interrupt */ >> + omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4); >> + >> + } else if (status & DES_REG_IRQ_DATA_OUT) { >> + omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); >> + >> + BUG_ON(!dd->out_sg); >> + >> + BUG_ON(_calc_walked(out) > dd->out_sg->length); >> + >> + dst = sg_virt(dd->out_sg) + _calc_walked(out); >> + >> + for (i = 0; i < DES_BLOCK_WORDS; i++) { >> + *dst = omap_des_read(dd, DES_REG_DATA_N(dd, i)); >> + scatterwalk_advance(&dd->out_walk, 4); >> + if (dd->out_sg->length == _calc_walked(out)) { >> + dd->out_sg = scatterwalk_sg_next(dd->out_sg); >> + if (dd->out_sg) { >> + scatterwalk_start(&dd->out_walk, >> + dd->out_sg); >> + dst = sg_virt(dd->out_sg) + >> + _calc_walked(out); >> + } >> + } else { >> + dst++; >> + } >> + } >> + >> + dd->total -= DES_BLOCK_SIZE; >> + >> + BUG_ON(dd->total < 0); >> + >> + /* Clear IRQ status */ >> + status &= ~DES_REG_IRQ_DATA_OUT; >> + omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); >> + >> + if (!dd->total) >> + /* All bytes read! */ >> + tasklet_schedule(&dd->done_task); >> + else >> + /* Enable DATA_IN interrupt for next block */ >> + omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); >> + } >> + >> + return IRQ_HANDLED; >> +} >> + >> +static const struct of_device_id omap_des_of_match[] = { >> + { >> + .compatible = "ti,omap4-des", >> + .data = &omap_des_pdata_omap4, >> + }, >> + {}, >> +}; >> +MODULE_DEVICE_TABLE(of, omap_des_of_match); >> + >> +static int omap_des_get_res_of(struct omap_des_dev *dd, >> + struct device *dev, struct resource *res) >> +{ >> + struct device_node *node = dev->of_node; >> + const struct of_device_id *match; >> + int err = 0; >> + >> + match = of_match_device(of_match_ptr(omap_des_of_match), dev); >> + if (!match) { >> + dev_err(dev, "no compatible OF match\n"); >> + err = -EINVAL; >> + goto err; >> + } >> + >> + err = of_address_to_resource(node, 0, res); > > Do you really need to do this? DT should have already populated > a resource for you based on the 'reg' property. Ok, thanks. Now will do: *res = platform_get_resource(pdev, IORESOURCE_MEM); >> + if (err < 0) { >> + dev_err(dev, "can't translate OF node address\n"); >> + err = -EINVAL; >> + goto err; >> + } >> + >> + dd->dma_out = -1; /* Dummy value that's unused */ >> + dd->dma_in = -1; /* Dummy value that's unused */ >> + >> + dd->pdata = match->data; >> + >> +err: >> + return err; >> +} >> +#else >> +static const struct of_device_id omap_des_of_match[] = { >> + {}, >> +}; > > you don't need this if you use of_match_ptr() Ok I changed it to: + .of_match_table = of_match_ptr(omap_des_of_match), and removed empty definition for !CONFIG_OF. >> + >> +static int omap_des_get_res_of(struct omap_des_dev *dd, >> + struct device *dev, struct resource *res) >> +{ >> + return -EINVAL; >> +} >> +#endif >> + >> +static int omap_des_get_res_pdev(struct omap_des_dev *dd, >> + struct platform_device *pdev, struct resource *res) >> +{ >> + struct device *dev = &pdev->dev; >> + struct resource *r; >> + int err = 0; >> + >> + /* Get the base address */ >> + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + if (!r) { >> + dev_err(dev, "no MEM resource info\n"); >> + err = -ENODEV; >> + goto err; >> + } >> + memcpy(res, r, sizeof(*res)); > > I don't think you need any of this. Regardless of a DT or a > non-DT platform, you should be able to do a platform_get_resource() > for mem resources. Yes ok, I removed all this and am directly using the res pointer now instead of pre-filling a structure. Also both DT/non-DT paths now use platform_get_resource. [..] >> + tasklet_kill(&dd->done_task); >> + tasklet_kill(&dd->queue_task); >> + omap_des_dma_cleanup(dd); >> + pm_runtime_disable(dd->dev); >> + dd = NULL; >> + >> + return 0; >> +} >> + >> +#ifdef CONFIG_PM_SLEEP >> +static int omap_des_suspend(struct device *dev) >> +{ >> + pm_runtime_put_sync(dev); > > I know you seemed to have taken this from the omap-aes driver, but this > does not seem correct. Your system suspend callbacks shouldn't > really be using pm_runtime apis. > On OMAPs this is handled by the pm_domain level callbacks, in case > your device is not runtime suspended during system suspend. Can you suggest how else to handle this? >> + return 0; >> +} >> + >> +static int omap_des_resume(struct device *dev) >> +{ >> + pm_runtime_get_sync(dev); > > Same here. > Btw, has the omap-aes or this driver been tested with system > suspend on any platfoms? Yes, omap-aes has been successfully tested with Suspend/Resume on AM335x platforms. >> + return 0; >> +} >> +#endif >> + >> +static const struct dev_pm_ops omap_des_pm_ops = { >> + SET_SYSTEM_SLEEP_PM_OPS(omap_des_suspend, omap_des_resume) >> +}; >> + >> +static struct platform_driver omap_des_driver = { >> + .probe = omap_des_probe, >> + .remove = omap_des_remove, >> + .driver = { >> + .name = "omap-des", >> + .owner = THIS_MODULE, >> + .pm = &omap_des_pm_ops, >> + .of_match_table = omap_des_of_match, > > You could use of_match_ptr() here and avoid having the empty > omap_des_of_match defined. Done, thanks. Regards, -Joel >> + }, >> +}; >> + >> +module_platform_driver(omap_des_driver); >> + >> +MODULE_DESCRIPTION("OMAP DES hw acceleration support."); >> +MODULE_LICENSE("GPL v2"); >> +MODULE_AUTHOR("Joel Fernandes <joelf@xxxxxx>"); >> > -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html