blob: 42ee94fe678d8dcfc113fa457cb5698b0efa6558 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/lc823450/lc823450_procfs_dvfs.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/procfs.h>
#include <arch/irq.h>
#include "lc823450_dvfs2.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define DVFS_LINELEN 128
/****************************************************************************
* Private Types
****************************************************************************/
struct dvfs_file_s
{
struct procfs_file_s base; /* Base open file structure */
unsigned int linesize; /* Number of valid characters in line[] */
char line[DVFS_LINELEN]; /* Pre-allocated buffer for formatted lines */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int dvfs_open(struct file *filep, const char *relpath,
int oflags, mode_t mode);
static int dvfs_close(struct file *filep);
static ssize_t dvfs_read(struct file *filep, char *buffer,
size_t buflen);
static ssize_t dvfs_write(struct file *filep, const char *buffer,
size_t buflen);
static int dvfs_dup(const struct file *oldp,
struct file *newp);
static int dvfs_stat(const char *relpath, struct stat *buf);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct procfs_operations dvfs_procfsoperations =
{
dvfs_open, /* open */
dvfs_close, /* close */
dvfs_read, /* read */
dvfs_write, /* write */
dvfs_dup, /* dup */
NULL, /* opendir */
NULL, /* closedir */
NULL, /* readdir */
NULL, /* rewinddir */
dvfs_stat /* stat */
};
static const struct procfs_entry_s g_procfs_dvfs =
{
"dvfs",
&dvfs_procfsoperations
};
/****************************************************************************
* Public Data
****************************************************************************/
extern int8_t g_dvfs_enabled;
extern int8_t g_dvfs_auto;
extern uint16_t g_dvfs_cur_freq;
extern uint32_t g_dvfs_freq_stat[3];
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: dvfs_open
****************************************************************************/
static int dvfs_open(struct file *filep, const char *relpath,
int oflags, mode_t mode)
{
struct dvfs_file_s *priv;
finfo("Open '%s'\n", relpath);
/* Allocate a container to hold the task and attribute selection */
priv = kmm_zalloc(sizeof(struct dvfs_file_s));
if (!priv)
{
ferr("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* Save the index as the open-specific state in filep->f_priv */
filep->f_priv = (void *)priv;
return OK;
}
/****************************************************************************
* Name: dvfs_close
****************************************************************************/
static int dvfs_close(struct file *filep)
{
struct dvfs_file_s *priv;
/* Recover our private data from the struct file instance */
priv = (struct dvfs_file_s *)filep->f_priv;
DEBUGASSERT(priv);
/* Release the file attributes structure */
kmm_free(priv);
filep->f_priv = NULL;
return OK;
}
/****************************************************************************
* Name: dvfs_read
****************************************************************************/
static ssize_t dvfs_read(struct file *filep, char *buffer,
size_t buflen)
{
struct dvfs_file_s *priv;
size_t linesize;
size_t copysize;
size_t remaining;
size_t totalsize;
off_t offset = filep->f_pos;
int i;
uint64_t idletime[CONFIG_SMP_NCPUS];
finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
priv = (struct dvfs_file_s *)filep->f_priv;
DEBUGASSERT(priv);
remaining = buflen;
totalsize = 0;
linesize = snprintf(priv->line,
DVFS_LINELEN,
"cur_freq %d\n", g_dvfs_cur_freq);
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
totalsize += copysize;
buffer += copysize;
remaining -= copysize;
if (totalsize >= buflen)
{
return totalsize;
}
linesize = snprintf(priv->line,
DVFS_LINELEN,
"enable %d\n", g_dvfs_enabled);
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
totalsize += copysize;
buffer += copysize;
remaining -= copysize;
linesize = snprintf(priv->line,
DVFS_LINELEN,
"auto %d\n", g_dvfs_auto);
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
totalsize += copysize;
buffer += copysize;
remaining -= copysize;
linesize = snprintf(priv->line,
DVFS_LINELEN,
"fstat %" PRId32 " %" PRId32 " %" PRId32 "\n",
g_dvfs_freq_stat[0],
g_dvfs_freq_stat[1],
g_dvfs_freq_stat[2]);
copysize = procfs_memcpy(priv->line, linesize, buffer, remaining, &offset);
totalsize += copysize;
buffer += copysize;
remaining -= copysize;
lc823450_dvfs_get_idletime(idletime);
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
{
linesize = snprintf(priv->line,
DVFS_LINELEN,
"idle%d %lld\n",
i, idletime[i]);
copysize = procfs_memcpy(priv->line, linesize, buffer,
remaining, &offset);
totalsize += copysize;
buffer += copysize;
remaining -= copysize;
}
/* Update the file offset */
if (totalsize > 0)
{
filep->f_pos += totalsize;
}
return totalsize;
}
/****************************************************************************
* Name: procfs_write
****************************************************************************/
static ssize_t dvfs_write(struct file *filep, const char *buffer,
size_t buflen)
{
char line[DVFS_LINELEN];
char cmd[16];
int n;
int tmp;
n = MIN(buflen, DVFS_LINELEN);
strlcpy(line, buffer, n);
n = strcspn(line, " ");
n = MIN(n, sizeof(cmd));
strlcpy(cmd, line, n);
if (0 == strcmp(cmd, "cur_freq"))
{
tmp = atoi(line + (n + 1));
lc823450_dvfs_set_freq(tmp);
}
else if (0 == strcmp(cmd, "enable"))
{
tmp = atoi(line + (n + 1));
g_dvfs_enabled = tmp;
}
else if (0 == strcmp(cmd, "auto"))
{
tmp = atoi(line + (n + 1));
g_dvfs_auto = tmp;
}
else
{
serr("ERROR: %s not supported.\n", cmd);
}
return buflen;
}
/****************************************************************************
* Name: dvfs_dup
****************************************************************************/
static int dvfs_dup(const struct file *oldp, struct file *newp)
{
struct dvfs_file_s *oldpriv;
struct dvfs_file_s *newpriv;
finfo("Dup %p->%p\n", oldp, newp);
/* Recover our private data from the old struct file instance */
oldpriv = (struct dvfs_file_s *)oldp->f_priv;
DEBUGASSERT(oldpriv);
/* Allocate a new container to hold the task and attribute selection */
newpriv = kmm_zalloc(sizeof(struct dvfs_file_s));
if (!newpriv)
{
ferr("ERROR: Failed to allocate file attributes\n");
return -ENOMEM;
}
/* The copy the file attributes from the old attributes to the new */
memcpy(newpriv, oldpriv, sizeof(struct dvfs_file_s));
/* Save the new attributes in the new file structure */
newp->f_priv = (void *)newpriv;
return OK;
}
/****************************************************************************
* Name: dvfs_stat
****************************************************************************/
static int dvfs_stat(const char *relpath, struct stat *buf)
{
buf->st_mode =
S_IFREG |
S_IROTH | S_IWOTH |
S_IRGRP | S_IWGRP |
S_IRUSR | S_IWUSR;
buf->st_size = 0;
buf->st_blksize = 0;
buf->st_blocks = 0;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: dvfs_procfs_register
****************************************************************************/
int dvfs_procfs_register(void)
{
return procfs_register(&g_procfs_dvfs);
}