Why execute iowrite32() after ioread32() from an register in ccp driver included in kernel? - io

It's in drivers/crypto/ccp/ccp-dev-v5.c.
ccp is coprocessor used for crypto. ccp5_irq_bh() is an interrupt handler function.
Now that status is read from that register, why write it again below? That doesn't make sense.
Code is:
static void ccp5_irq_bh(unsigned long data)
{
struct ccp_device *ccp = (struct ccp_device *)data;
u32 status;
unsigned int i;
for (i = 0; i < ccp->cmd_q_count; i++) {
struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
status = ioread32(cmd_q->reg_interrupt_status);
if (status) {
cmd_q->int_status = status;
cmd_q->q_status = ioread32(cmd_q->reg_status);
cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
/* On error, only save the first error value */
if ((status & INT_ERROR) && !cmd_q->cmd_error)
cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
cmd_q->int_rcvd = 1;
/* Acknowledge the interrupt and wake the kthread */
iowrite32(status, cmd_q->reg_interrupt_status);
wake_up_interruptible(&cmd_q->int_queue);
}
}
ccp5_enable_queue_interrupts(ccp);
}

Related

Why Input/Output Error occurs when use ls command in my fuse filesystem?

Why I/O Error causes when I tried ls . command in my fuse filesystem?
My filesystem has a limitation that it only allows mail address type as individual filename and it does not allows sub directory.
Now I want to display a list of file name when use ls . but it does not work.
I understood that it must implement a callback function. (Correspond function is ll_readdir in mycode)
but I have no idea what points are causes the errors.
Update:
Now I use strace command to investigate what system call raise a this error.
According to result of strace, this error caused in getdents64 syscall.
getdents64(3, 0x5611ed000540, 32768) = -1 EIO (Input/output error)
Code1 (implementation of mm:
struct mutex_map {
int counter = 2;
std::mutex _mtx;
std::unordered_map<int, std::string> _data;
std::unordered_map<std::string, int> _rev_data;
public:
int set_value(const char* value) {
std::string s = std::string(value);
std::lock_guard<std::mutex> lock(_mtx);
counter++;
_data[counter] = s;
_rev_data[s] = counter;
return counter;
}
const char* get_value(int key) { return _data[key].c_str(); }
int get_ino(const char* name) { return _rev_data[std::string(name)]; }
};
static mutex_map mm;
Code2: (sendmailfs_stat)
static int sendmailfs_stat(fuse_ino_t ino, struct stat* stbuf,
size_t name_length) {
uid_t uid = getuid();
gid_t gid = getgid();
stbuf->st_ino = ino;
if (ino == 1) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
stbuf->st_uid = uid;
stbuf->st_mode = S_IFDIR;
} else {
stbuf->st_mode = S_IFCHR | 0666;
stbuf->st_nlink = 1;
stbuf->st_size = name_length;
stbuf->st_uid = uid;
stbuf->st_gid = gid;
}
return 0;
}
Code 3: (implementation of readdir callback)
static void ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info* fi) {
// printf("size_t=%ld, fh=%ld, ino=%ld\n", size, fi->fh, ino);
if (ino == 1) {
off_t o = 0;
size_t rest = size;
size_t res;
char* buf = (char*)calloc(1, size);
struct stat dotst;
sendmailfs_stat(ino, &dotst, strlen("."));
res = fuse_add_direntry(req, buf, rest, ".", &dotst, o);
rest -= res;
o++;
printf("%s\n", "start of loop");
uint64_t num_contain = 0;
for (auto& c : mm._data) {
const char* t = c.second.c_str();
int ino2 = mm.get_ino(t);
struct stat st;
sendmailfs_stat(ino2, &st, strlen(t));
fuse_entry_param e;
e.ino = ino2;
e.attr_timeout = 0;
sendmailfs_stat(ino2, &e.attr, strlen(t));
res = fuse_add_direntry_plus(req, buf, rest, t, &e, o);
o += 1;
rest -= res;
}
fuse_reply_buf(req, buf, size);
}
}
A bit late, but if anyone having this error stumbles upon this thread, they might want to check first whether the filesystem is mounted properly. The Input/output error from getdents64 is symptomatic of a filesystem that was unmounted, but failed for some reason (like a file was still in use when user tried the umount command), so still looks mounted, but no data can be fetched from it.
So in this case, some process could be calling umount (and failing) before you run ls, or the filesystem failed to correctly mount in the first place for some reason.

Linux kernel SPI driver does not enable CS before writing

I am trying to write a kernel space SPI driver, and have it communicate with an Arduino board, as a start.
I issue simple spi_write function in kernel space. The problem I'm having is that Chip Select or Slave Select (SS) is enabled when the driver is probed. After spi_write, it is disabled and never again set to HIGH. Therefore I am only able to write once from the linux kernel SPI driver.
The driver looks like follows:
#define MIBI_READ(mibi_priv, reg) ((mibi_priv)->bops->read((mibi_priv)->dev, reg))
#define MIBI_WRITE(mibi_priv, reg, val) ((mibi_priv)->bops->write((mibi_priv)->dev, reg, val))
struct spi_bus_ops {
u16 bustype;
int (*read)(struct device *, unsigned char);
int (*read_block)(struct device *, unsigned char, int, void *);
int (*write)(struct device *, unsigned char, unsigned char);
};
struct mibi {
struct device *dev;
const struct spi_bus_ops *bops;
};
static const struct spi_bus_ops spi_bops = {
.bustype = BUS_SPI,
.write = mibi_spi_write,
.read = mibi_spi_read,
.read_block = mibi_spi_read_block,
};
static int mibi_spi_probe(struct spi_device *spi)
{
struct mibi *mibi_priv;
dev_info(&spi->dev, "mibi_spi probed\n");
/* send the spi operations */
mibi_priv = mibi_probe(&spi->dev, &spi_bops);
if (IS_ERR(mibi_priv))
return PTR_ERR(mibi_priv);
/* Attach the SPI device to the private structure */
spi_set_drvdata(spi, mibi_priv);
dev_info(&spi->dev, "mibi_spi exited\n");
return 0;
}
static int mibi_spi_write(struct device *dev,
unsigned char reg, unsigned char val)
{
struct spi_device *spi = to_spi_device(dev);
dev_info(dev, "mibi_spi_write entered\n");
u8 buf[2];
buf[0] = reg;
buf[1] = val;
dev_info(dev, "mibi_spi_write exited\n");
return spi_write(spi, buf, sizeof(buf));
}
struct mibi *mibi_probe(struct device *dev,
const struct spi_bus_ops *bops)
{
struct mibi *mibi_priv; /* declare our private structure */
struct spi_device *spi = to_spi_device(dev);
int err, ret;
u8 revid;
dev_info(dev, "mibi probed\n");
/* Allocate private structure*/
mibi_priv = devm_kzalloc(dev, sizeof(*mibi_priv), GFP_KERNEL);
if (!mibi_priv) {
dev_err(dev, "Failed to allocate memory\n");
err = -ENOMEM;
goto err_out;
}
/* Initialize our private structure */
mibi_priv->dev = dev;
/* Store the SPI operations in our private structure */
mibi_priv->bops = bops;
/* Sysfs registration */
ret = sysfs_create_group(&spi->dev.kobj, &mibi_sysfs_group);
if (ret < 0)
{
dev_err(dev, "Couldn't register sysfs group\n");
return ret;
}
dev_info(dev, "mibi exited\n");
return mibi_priv;
err_out:
return ERR_PTR(err);
}
Devicetree looks like follows:
&spi0 {
mibi0: mibi#0 {
compatible = "mibi";
reg = <0>;
spi-max-frequency = <5000000>;
};
spidev0: spidev#0 {
compatible = "spidev";
reg = <0>;
spi-max-frequency = <125000000>;
};
};
From a sysfs callback, I simply call MIBI_WRITE(mibi_priv, 0x01, 0x06);.
Arduino side looks like follows:
//Initialize SPI slave.
void SlaveInit(void) {
// Initialize SPI pins.
pinMode(SCK, INPUT);
pinMode(MOSI, INPUT);
pinMode(MISO, INPUT);
pinMode(SS, INPUT);
// Enable SPI as slave.
SPCR = (1 << SPE);
}
// SPI Transfer.
byte SPItransfer(byte value) {
SPDR = value;
while(!(SPSR & (1<<SPIF)));
delay(10);
return SPDR;
}
void setup() {
Serial.begin(9600);
SlaveInit();
}
void loop()
{
// Slave Enabled?
if (!digitalRead(SS)) {
// Yes, first time?
if (SSlast != LOW) {
// Yes, take MISO pin.
pinMode(MISO, OUTPUT);
Serial.println("***Slave Enabled.");
// Write -1 slave response code and receive master command code
byte rx = SPItransfer(255);
Serial.println("Initial -1 slave response code sent");
Serial.println("rx:" + String(rx) + ".");
// Update SSlast.
SSlast = LOW;
}
}
else {
// No, first time?
if (SSlast != HIGH) {
// Yes, release MISO pin.
pinMode(MISO, INPUT);
Serial.println("Slave Disabled.");
// Update SSlast.
SSlast = HIGH;
}
}
}
I am able to write once from Linux kernel to Arduino correctly, but then the SS is always low so I can not write anymore. What do you think I am missing here? Is there a way to make sure that SS changes as I call "spi_write"?
(Might the problem related to having spidev and mibi both attached to the same CS?)
I would appreciate general advice to achieving this as well as support for the solution to my problem. Thank you.
EDIT Chip Select is not modified still, even that I converted the driver to use Regmap-SPI. The situation is as before. I am able to write once to the Arduino. But Chip Select does not change after driver is probed. How do I handle Chip Select in Linux SPI subsystem? Find the final state of the driver as follows:
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/regmap.h>
/* Top level struct */
struct mibi_state {
struct regmap *regmap;
struct spi_device *spi;
u8 buffer[4];
};
/* IIO-Userspace communication channels */
#define MIBI_NUM_IIO_CHANNELS 2
static const struct iio_chan_spec mibi_channels[MIBI_NUM_IIO_CHANNELS] = {
{
.type = IIO_VOLTAGE,
.indexed = 1,
.output = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
{
.type = IIO_VOLTAGE,
.indexed = 1,
.output = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
};
/* IIO-Userspace communication read callback */
static int mibi_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
int ret;
struct mibi_state *st = iio_priv(indio_dev);
dev_info(&st->spi->dev, "Entered read_raw\n");
u32 read_value;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(st->regmap, 0x01, &read_value);
if (ret) {
dev_err(&st->spi->dev, "Error reading in read_raw callback\n");
return ret;
}
dev_info(&st->spi->dev, "regmap_read 0x01 %d\n",read_value);
*val = read_value;
dev_info(&st->spi->dev, "read_raw value %d\n", *val);
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
/* IIO-Userspace communication write callback */
static int mibi_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mibi_state *st = iio_priv(indio_dev);
u8 value;
value = 0;
dev_info(&st->spi->dev, "Entered write_raw\n");
switch (mask) {
case IIO_CHAN_INFO_RAW:
value = val;
dev_info(&st->spi->dev, "regmap_write 0x01 %d\n",value);
return regmap_write(st->regmap, 0x01, value);
default :
return -EINVAL;
}
}
/* IIO-Userspace communication */
static const struct iio_info mibi_info = {
.read_raw = &mibi_read_raw,
.write_raw = &mibi_write_raw,
};
/* Regmap-SPI config */
static const struct regmap_config mibi_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
/* Setting bits 7 and 6 enables multiple-byte read */
.read_flag_mask = BIT(7) | BIT(6),
};
/* Probe */
static int mibi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mibi_state *st;
struct regmap *regmap;
int err;
int ret;
dev_info(&spi->dev, "mibi_probe() entered.\n");
const struct spi_device_id *id = spi_get_device_id(spi);
/* Allocate IIO */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
/* Allocate regmap */
regmap = devm_regmap_init_spi(spi, &mibi_spi_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
PTR_ERR(regmap));
return PTR_ERR(regmap);
}
/* Populate top level struct */
st->regmap = regmap;
st->spi = spi;
/* Populate IIO struct */
indio_dev->dev.parent = &spi->dev;
indio_dev->channels = mibi_channels;
indio_dev->info = &mibi_info;
indio_dev->name = id->name;
indio_dev->num_channels = MIBI_NUM_IIO_CHANNELS;
indio_dev->modes = INDIO_DIRECT_MODE;
/* IIO Register */
err = devm_iio_device_register(&spi->dev, indio_dev);
if (err < 0)
return err;
ret = regmap_write(st->regmap, 0x01, 0x06);
if (ret < 0) {
dev_err(&spi->dev, "Error writing to device: %d\n", ret);
return ret;
}
return 0;
}
static const struct of_device_id mibi_dt_ids[] = {
{ .compatible = "mozcelikors,mibi", },
{ }
};
MODULE_DEVICE_TABLE(of, mibi_dt_ids);
static const struct spi_device_id mibi_id[] = {
{ .name = "mibi", },
{ }
};
MODULE_DEVICE_TABLE(spi, mibi_id);
static struct spi_driver mibi_driver = {
.driver = {
.name = "mibi",
.owner = THIS_MODULE,
.of_match_table = mibi_dt_ids,
},
.probe = mibi_probe,
.id_table = mibi_id,
};
module_spi_driver(mibi_driver);

custom memory allocator - segfault

me and my friend are trying to develop custom memory allocator in linux ubuntu 16.04.
We got stuck because of an error, btw its our first time
that we are trying to code something like that so we are not the best debuggers the error is : Segmentation fault (core dumped)
and here is the code.
can anybody help us understand whats wrong ?
Thank you!
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
struct header_t {
size_t size;
unsigned is_free;
struct header_t *next; };
struct header_t *head = NULL, *tail = NULL;
pthread_mutex_t global_malloc_lock;
struct header_t *get_free_block(size_t size)
{
struct header_t *curr = head;
while(curr) {
/* see if there's a free block that can accomodate requested size */
if (curr->is_free && curr->size >= size)
return curr;
curr = curr->next;
}
return NULL;
}
void free(void *block)
{
struct header_t *header, *tmp;
/* program break is the end of the
process's data segment */
void *programbreak;
if (!block)
return;
pthread_mutex_lock(&global_malloc_lock);
header = (struct header_t*)block - 1;
/* sbrk(0) gives the current program break address */
programbreak = sbrk(0);
/*
Check if the block to be freed is the last one in the
linked list. If it is, then we could shrink the size of the
heap and release memory to OS. Else, we will keep the block
but mark it as free. */
if ((char*)block + header->size == programbreak) {
if (head == tail) {
head = tail = NULL;
} else {
tmp = head;
while (tmp) {
if(tmp->next == tail) {
tmp->next = NULL;
tail = tmp;
}
tmp = tmp->next;
}
}
/* sbrk() with a negative argument decrements the program break.
So memory is released by the program to OS. */
sbrk(0 - header->size - sizeof(struct header_t));
/* Note: This lock does not really assure thread
safety, because sbrk() itself is not really
thread safe. Suppose there occurs a foregin sbrk(N)
after we find the program break and before we decrement
it, then we end up realeasing the memory obtained by
the foreign sbrk(). */
pthread_mutex_unlock(&global_malloc_lock);
return;
}
header->is_free = 1;
pthread_mutex_unlock(&global_malloc_lock);
}
void *malloc(size_t size)
{
size_t total_size;
void *block;
struct header_t *header;
if (!size)
return NULL;
pthread_mutex_lock(&global_malloc_lock);
header = get_free_block(size);
if (header) {
/* Woah, found a free block to accomodate requested memory. */
header->is_free = 0;
pthread_mutex_unlock(&global_malloc_lock);
return (void*)(header + 1);
}
/* We need to get memory to fit in the requested block and header
from OS. */
total_size = sizeof(struct header_t) + size;
block = sbrk(total_size);
if (block == (void*) -1) {
pthread_mutex_unlock(&global_malloc_lock);
return NULL;
}
header = block;
header->size = size;
header->is_free = 0;
header->next = NULL;
if (!head)
head = header;
if (tail)
tail->next = header;
tail = header;
pthread_mutex_unlock(&global_malloc_lock);
return (void*)(header + 1);
}
void *calloc(size_t num, size_t nsize)
{
size_t size;
void *block;
if (!num || !nsize)
return NULL;
size = num * nsize;
/* check mul overflow */
if (nsize != size / num)
return NULL;
block = malloc(size);
if (!block)
return NULL;
memset(block, 0, size);
return block;
}
void *realloc(void *block, size_t size)
{
struct header_t *header;
void *ret;
if (!block || !size)
return malloc(size);
header = (struct header_t*)block - 1;
if (header->size >= size)
return block;
ret = malloc(size);
if (ret) {
/* Relocate contents to the new bigger block */
memcpy(ret, block, header->size);
/* Free the old memory block */
free(block);
}
return ret;
}
The problem occurred because the functions were not prototyped [decalred].
Once I added functions prototype. The code worked.
For more information about prototyping: http://www.trytoprogram.com/c-programming/function-prototype-in-c/
mutex variable should be initialized before using it for applying lock. your global_malloc_lock is not initialized.
you can't initialize mutex variable as of normal variable.
pthread_mutex_t global_malloc_lock = 0 ;// invalid .. you may thinking since it's it declared as global it's initialized with 0 which is wrong
Initialize the mutex variable by calling pthread_mutex_init() or using PTHREAD_MUTEX_INITIALIZER ;
for your code add this
pthread_mutex_t global_malloc_lock = pthread_mutex_t global_malloc_lock;

FreeBSD kqueue filter only sometimes unblocks the waiting client

I am writing kqueue hooks for a character device that allows a client to block waiting for an EVFILT_READ. If I set my read filters code to always return one the kevent will return instantly. However, if the filter returns one at some later point in time nothing unblocks. For the following code the printf "After" never happens and in the filter code I can trivially get "filter_Read return 1" (immediately followed by a return 0)
Device (relevant excerpt)
static int
lowmem_filter_read(struct knote *kn, long hint)
{
mtx_assert(&lowmem_mtx, MA_OWNED);
if(manual_alert){
manual_alert=0;
printf("filter_Read return 1\n");
return 1;
}
printf("filter_Read return 0\n");
return 0;
}
static void
lowmem_filter_detach(struct knote *kn)
{
mtx_assert(&lowmem_mtx, MA_OWNED);
knlist_remove(&kl, kn, 0);
}
static struct filterops lowmem_filtops_read = {
.f_isfd = 1,
.f_detach = lowmem_filter_detach,
.f_event = lowmem_filter_read,
};
static int
lowmem_kqfilter(struct cdev *dev, struct knote *kn)
{
int err = EINVAL;
/* Figure out who needs service */
lowmem_lock();
switch (kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &lowmem_filtops_read;
knlist_add(&kl, kn, 1);
err = 0;
break;
default:
err = EOPNOTSUPP;
break;
}
lowmem_unlock();
return (err);
}
Client:
struct kevent ev;
struct timespec nullts = {0,0};
int fd=0;
int main(int argc, char **argv){
fd = open("/dev/lowmem", O_RDWR | O_NONBLOCK);
int kq=kqueue();
EV_SET(&ev,fd,EVFILT_READ, EV_ADD,0,0,NULL);
kevent(kq,&ev,1,NULL,0,&nullts);
for(;;){
printf("Starting\n");
int n=kevent(kq,NULL,0,&ev,1,NULL);
printf("After\n");
if(n>0){
printf("Something happened ev.fflags=%i\n",(int)ev.fflags);
}
}
return 0;
}

Linux - Control Flow in a linux kernel module

I am learning to write kernel modules and in one of the examples I had to make sure that a thread executed 10 times and exits, so I wrote this according to what I have studied:
#include <linux/module.h>
#include <linux/kthread.h>
struct task_struct *ts;
int flag = 0;
int id = 10;
int function(void *data) {
int n = *(int*)data;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(n*HZ); // after doing this it executed infinitely and i had to reboot
while(!kthread_should_stop()) {
printk(KERN_EMERG "Ding");
}
flag = 1;
return 0;
}
int init_module (void) {
ts = kthread_run(function, (void *)&id, "spawn");
return 0;
}
void cleanup_module(void) {
if (flag==1) { return; }
else { if (ts != NULL) kthread_stop(ts);
}
return;
}
MODULE_LICENSE("GPL");
What I want to know is :
a) How to make thread execute 10 times like a loop
b) How does the control flows in these kind of processes that is if we make it to execute 10 times then does it go back and forth between function and cleanup_module or init_module or what exactly happens?
If you control kthread with kthread_stop, the kthread shouldn't exit until be ing stopped (see also that answer). So, after executing all operations, kthread should wait until stopped.
Kernel already implements kthread_worker mechanism, when kthread just executes works, added to it.
DEFINE_KTHREAD_WORKER(worker);
struct my_work
{
struct kthread_work *work; // 'Base' class
int n;
};
void do_work(struct kthread_work *work)
{
struct my_work* w = container_of(work, struct my_work, work);
printk(KERN_EMERG "Ding %d", w->n);
// And free work struct at the end
kfree(w);
}
int init_module (void) {
int i;
for(i = 0; i < 10; i++)
{
struct my_work* w = kmalloc(sizeof(struct my_work), GFP_KERNEL);
init_kthread_work(&w->work, &do_work);
w->n = i + 1;
queue_kthread_work(&worker, &w->work);
}
ts = kthread_run(&kthread_worker_fn, &worker, "spawn");
return 0;
}
void cleanup_module(void) {
kthread_stop(ts);
}

Resources