linux/drivers/dma/qcom/hidma_dbg.c
<<
>>
Prefs
   1/*
   2 * Qualcomm Technologies HIDMA debug file
   3 *
   4 * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 and
   8 * only version 2 as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/debugfs.h>
  17#include <linux/device.h>
  18#include <linux/list.h>
  19#include <linux/pm_runtime.h>
  20
  21#include "hidma.h"
  22
  23static void hidma_ll_chstats(struct seq_file *s, void *llhndl, u32 tre_ch)
  24{
  25        struct hidma_lldev *lldev = llhndl;
  26        struct hidma_tre *tre;
  27        u32 length;
  28        dma_addr_t src_start;
  29        dma_addr_t dest_start;
  30        u32 *tre_local;
  31
  32        if (tre_ch >= lldev->nr_tres) {
  33                dev_err(lldev->dev, "invalid TRE number in chstats:%d", tre_ch);
  34                return;
  35        }
  36        tre = &lldev->trepool[tre_ch];
  37        seq_printf(s, "------Channel %d -----\n", tre_ch);
  38        seq_printf(s, "allocated=%d\n", atomic_read(&tre->allocated));
  39        seq_printf(s, "queued = 0x%x\n", tre->queued);
  40        seq_printf(s, "err_info = 0x%x\n", tre->err_info);
  41        seq_printf(s, "err_code = 0x%x\n", tre->err_code);
  42        seq_printf(s, "status = 0x%x\n", tre->status);
  43        seq_printf(s, "idx = 0x%x\n", tre->idx);
  44        seq_printf(s, "dma_sig = 0x%x\n", tre->dma_sig);
  45        seq_printf(s, "dev_name=%s\n", tre->dev_name);
  46        seq_printf(s, "callback=%p\n", tre->callback);
  47        seq_printf(s, "data=%p\n", tre->data);
  48        seq_printf(s, "tre_index = 0x%x\n", tre->tre_index);
  49
  50        tre_local = &tre->tre_local[0];
  51        src_start = tre_local[HIDMA_TRE_SRC_LOW_IDX];
  52        src_start = ((u64) (tre_local[HIDMA_TRE_SRC_HI_IDX]) << 32) + src_start;
  53        dest_start = tre_local[HIDMA_TRE_DEST_LOW_IDX];
  54        dest_start += ((u64) (tre_local[HIDMA_TRE_DEST_HI_IDX]) << 32);
  55        length = tre_local[HIDMA_TRE_LEN_IDX];
  56
  57        seq_printf(s, "src=%pap\n", &src_start);
  58        seq_printf(s, "dest=%pap\n", &dest_start);
  59        seq_printf(s, "length = 0x%x\n", length);
  60}
  61
  62static void hidma_ll_devstats(struct seq_file *s, void *llhndl)
  63{
  64        struct hidma_lldev *lldev = llhndl;
  65
  66        seq_puts(s, "------Device -----\n");
  67        seq_printf(s, "lldev init = 0x%x\n", lldev->initialized);
  68        seq_printf(s, "trch_state = 0x%x\n", lldev->trch_state);
  69        seq_printf(s, "evch_state = 0x%x\n", lldev->evch_state);
  70        seq_printf(s, "chidx = 0x%x\n", lldev->chidx);
  71        seq_printf(s, "nr_tres = 0x%x\n", lldev->nr_tres);
  72        seq_printf(s, "trca=%p\n", lldev->trca);
  73        seq_printf(s, "tre_ring=%p\n", lldev->tre_ring);
  74        seq_printf(s, "tre_ring_handle=%pap\n", &lldev->tre_dma);
  75        seq_printf(s, "tre_ring_size = 0x%x\n", lldev->tre_ring_size);
  76        seq_printf(s, "tre_processed_off = 0x%x\n", lldev->tre_processed_off);
  77        seq_printf(s, "pending_tre_count=%d\n",
  78                        atomic_read(&lldev->pending_tre_count));
  79        seq_printf(s, "evca=%p\n", lldev->evca);
  80        seq_printf(s, "evre_ring=%p\n", lldev->evre_ring);
  81        seq_printf(s, "evre_ring_handle=%pap\n", &lldev->evre_dma);
  82        seq_printf(s, "evre_ring_size = 0x%x\n", lldev->evre_ring_size);
  83        seq_printf(s, "evre_processed_off = 0x%x\n", lldev->evre_processed_off);
  84        seq_printf(s, "tre_write_offset = 0x%x\n", lldev->tre_write_offset);
  85}
  86
  87/*
  88 * hidma_chan_stats: display HIDMA channel statistics
  89 *
  90 * Display the statistics for the current HIDMA virtual channel device.
  91 */
  92static int hidma_chan_stats(struct seq_file *s, void *unused)
  93{
  94        struct hidma_chan *mchan = s->private;
  95        struct hidma_desc *mdesc;
  96        struct hidma_dev *dmadev = mchan->dmadev;
  97
  98        pm_runtime_get_sync(dmadev->ddev.dev);
  99        seq_printf(s, "paused=%u\n", mchan->paused);
 100        seq_printf(s, "dma_sig=%u\n", mchan->dma_sig);
 101        seq_puts(s, "prepared\n");
 102        list_for_each_entry(mdesc, &mchan->prepared, node)
 103                hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
 104
 105        seq_puts(s, "active\n");
 106        list_for_each_entry(mdesc, &mchan->active, node)
 107                hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
 108
 109        seq_puts(s, "completed\n");
 110        list_for_each_entry(mdesc, &mchan->completed, node)
 111                hidma_ll_chstats(s, mchan->dmadev->lldev, mdesc->tre_ch);
 112
 113        hidma_ll_devstats(s, mchan->dmadev->lldev);
 114        pm_runtime_mark_last_busy(dmadev->ddev.dev);
 115        pm_runtime_put_autosuspend(dmadev->ddev.dev);
 116        return 0;
 117}
 118
 119/*
 120 * hidma_dma_info: display HIDMA device info
 121 *
 122 * Display the info for the current HIDMA device.
 123 */
 124static int hidma_dma_info(struct seq_file *s, void *unused)
 125{
 126        struct hidma_dev *dmadev = s->private;
 127        resource_size_t sz;
 128
 129        seq_printf(s, "nr_descriptors=%d\n", dmadev->nr_descriptors);
 130        seq_printf(s, "dev_trca=%p\n", &dmadev->dev_trca);
 131        seq_printf(s, "dev_trca_phys=%pa\n", &dmadev->trca_resource->start);
 132        sz = resource_size(dmadev->trca_resource);
 133        seq_printf(s, "dev_trca_size=%pa\n", &sz);
 134        seq_printf(s, "dev_evca=%p\n", &dmadev->dev_evca);
 135        seq_printf(s, "dev_evca_phys=%pa\n", &dmadev->evca_resource->start);
 136        sz = resource_size(dmadev->evca_resource);
 137        seq_printf(s, "dev_evca_size=%pa\n", &sz);
 138        return 0;
 139}
 140
 141static int hidma_chan_stats_open(struct inode *inode, struct file *file)
 142{
 143        return single_open(file, hidma_chan_stats, inode->i_private);
 144}
 145
 146static int hidma_dma_info_open(struct inode *inode, struct file *file)
 147{
 148        return single_open(file, hidma_dma_info, inode->i_private);
 149}
 150
 151static const struct file_operations hidma_chan_fops = {
 152        .open = hidma_chan_stats_open,
 153        .read = seq_read,
 154        .llseek = seq_lseek,
 155        .release = single_release,
 156};
 157
 158static const struct file_operations hidma_dma_fops = {
 159        .open = hidma_dma_info_open,
 160        .read = seq_read,
 161        .llseek = seq_lseek,
 162        .release = single_release,
 163};
 164
 165void hidma_debug_uninit(struct hidma_dev *dmadev)
 166{
 167        debugfs_remove_recursive(dmadev->debugfs);
 168}
 169
 170int hidma_debug_init(struct hidma_dev *dmadev)
 171{
 172        int rc = 0;
 173        int chidx = 0;
 174        struct list_head *position = NULL;
 175
 176        dmadev->debugfs = debugfs_create_dir(dev_name(dmadev->ddev.dev), NULL);
 177        if (!dmadev->debugfs) {
 178                rc = -ENODEV;
 179                return rc;
 180        }
 181
 182        /* walk through the virtual channel list */
 183        list_for_each(position, &dmadev->ddev.channels) {
 184                struct hidma_chan *chan;
 185
 186                chan = list_entry(position, struct hidma_chan,
 187                                  chan.device_node);
 188                sprintf(chan->dbg_name, "chan%d", chidx);
 189                chan->debugfs = debugfs_create_dir(chan->dbg_name,
 190                                                   dmadev->debugfs);
 191                if (!chan->debugfs) {
 192                        rc = -ENOMEM;
 193                        goto cleanup;
 194                }
 195                chan->stats = debugfs_create_file("stats", S_IRUGO,
 196                                                  chan->debugfs, chan,
 197                                                  &hidma_chan_fops);
 198                if (!chan->stats) {
 199                        rc = -ENOMEM;
 200                        goto cleanup;
 201                }
 202                chidx++;
 203        }
 204
 205        dmadev->stats = debugfs_create_file("stats", S_IRUGO,
 206                                            dmadev->debugfs, dmadev,
 207                                            &hidma_dma_fops);
 208        if (!dmadev->stats) {
 209                rc = -ENOMEM;
 210                goto cleanup;
 211        }
 212
 213        return 0;
 214cleanup:
 215        hidma_debug_uninit(dmadev);
 216        return rc;
 217}
 218