kent: redesign api

This also got the dmabuf refcount hard fault issue resolved somehow.
Don't ask how or why, i'm just glad it works now.
This commit is contained in:
anna 2021-02-28 01:28:07 +01:00
parent 5fa7639ce8
commit 4349420217
Signed by: fef
GPG key ID: EC22E476DC2D3D84
8 changed files with 100 additions and 48 deletions

View file

@ -127,8 +127,8 @@ void irq_uart(void)
/* REG_UART_PDC_TCR has reached zero */
if (state & REG_UART_SR_ENDTX_MASK) {
/* this might be NULL but that's ok because free() tolerates that */
dmabuf_put(arch_serial_default_device.tx_current);
if (arch_serial_default_device.tx_current != NULL)
dmabuf_put(arch_serial_default_device.tx_current);
/* DMA automatically does this to the actual hardware registers */
arch_serial_default_device.tx_current = arch_serial_default_device.tx_next;

View file

@ -16,7 +16,7 @@ struct device {
};
/** Cast a kent out to its containing struct device */
#define to_device(ptr) container_of(ptr, struct device, kent)
#define kent_to_device(ptr) container_of(ptr, struct device, kent)
extern struct kent *devices_kent;
@ -27,10 +27,9 @@ int devices_init(void);
* Initialize a device and add it to the device tree.
*
* @param dev: device to initialze
* @param parent: parent device (may me `NULL` if unapplicable)
* @returns 0 on success, or a negative error code on failure
*/
int device_init(struct device *dev, struct device *parent);
int device_init(struct device *dev);
/** Increment a device's reference counter. */
inline void device_get(struct device *dev)

View file

@ -13,8 +13,11 @@ struct dmabuf {
uint8_t data[0];
};
#define kent_to_dmabuf(ptr) container_of(ptr, struct dmabuf, kent)
/**
* Create a new DMA buffer and its corresponding kent.
* Use `dmabuf_get` and `dmabuf_put` for refcounting.
*
* @param dev: device to create the buffer for
* @param len: buffer length in bytes

View file

@ -25,7 +25,10 @@ struct kent_ops {
/**
* struct kent: Kernel Entity
*
* This is basically a primitive ripoff of the kobject system in Linux.
* This is basically a primitive ripoff of the kobject system in Linux, except
* there is no representation in a virtual filesystem and it is only really used
* to keeping track of hierarchial reference counting.
*
* The main purpose of kents is to provide a basic common abstraction layer for
* all modules and submodules of the Ardix kernel. kents are arranged in a tree
* structure, and use an atomic reference counter to keep track of when it is
@ -42,13 +45,23 @@ struct kent {
extern struct kent *kent_root;
/**
* Initialize a kent and increment its refcounter by one.
* Initialize to root kent.
* This should probably be called before bootstrapping anything else hooking
* into the kent hierarchy i guess.
*
* @param kent: The kent.
* @param parent: The parent kent.
* @returns A nonzero value on failure
* @returns a nonzero value on failure
*/
int kent_init(struct kent *kent, struct kent *parent);
int kent_root_init(void);
/**
* Initialize a kent and set its refcount to one.
* This will fail unless both the operations and parent members are initialized.
* The parent refcount is incremented.
*
* @param kent: the kent
* @returns a nonzero value on failure
*/
int kent_init(struct kent *kent);
/**
* Increment the reference counter.
@ -60,7 +73,7 @@ void kent_get(struct kent *kent);
/**
* Decrement the reference counter.
* If it reaches zero, the kent is destroyed by invoking the respective callback
* in the operations field.
* in the operations field and the parent reference counter is also decremented.
*
* @param kent: The kent.
*/

View file

@ -12,14 +12,14 @@
struct kent *devices_kent = NULL;
static void device_destroy(struct kent *kent)
static void devices_destroy(struct kent *kent)
{
struct device *dev = to_device(kent);
free(dev);
/* should never be executed because the root devices kent is immortal */
free(kent);
}
struct kent_ops devices_kent_ops = {
.destroy = &device_destroy,
.destroy = &devices_destroy,
};
/** Initialize the devices subsystem. */
@ -32,18 +32,33 @@ int devices_init(void)
if (devices_kent == NULL)
return -ENOMEM;
/* we don't need that because the root device kent lives forever */
devices_kent->operations = NULL;
devices_kent->parent = kent_root;
devices_kent->operations = &devices_kent_ops;
return kent_init(devices_kent, NULL);
return kent_init(devices_kent);
}
int device_init(struct device *dev, struct device *parent)
static void device_destroy(struct kent *kent)
{
struct device *dev = kent_to_device(kent);
free(dev);
}
struct kent_ops device_kent_ops = {
.destroy = &device_destroy,
};
int device_init(struct device *dev)
{
if (devices_kent == NULL)
return -ENOENT;
return kent_init(&dev->kent, devices_kent);
if (dev->kent.operations == NULL)
dev->kent.operations = &device_kent_ops;
if (dev->kent.parent == NULL)
dev->kent.parent = devices_kent;
return kent_init(&dev->kent);
}
/*

View file

@ -12,11 +12,11 @@
static void dmabuf_destroy(struct kent *kent)
{
struct dmabuf *buf = container_of(kent, struct dmabuf, kent);
struct dmabuf *buf = kent_to_dmabuf(kent);
free(buf);
}
static struct kent_ops dma_kent_ops = {
static struct kent_ops dmabuf_kent_ops = {
.destroy = &dmabuf_destroy,
};
@ -27,10 +27,11 @@ struct dmabuf *dmabuf_create(struct device *dev, size_t len)
if (buf == NULL)
return NULL;
buf->kent.operations = &dma_kent_ops;
buf->kent.parent = &dev->kent;
buf->kent.operations = &dmabuf_kent_ops;
err = kent_init(&buf->kent, &dev->kent);
if (err != 0) {
err = kent_init(&buf->kent);
if (err) {
free(buf);
return NULL;
}

View file

@ -2,33 +2,57 @@
/* See the end of this file for copyright, licensing, and warranty information. */
#include <ardix/atom.h>
#include <ardix/malloc.h>
#include <ardix/kent.h>
#include <ardix/list.h>
#include <errno.h>
#include <stddef.h>
struct kent *kent_root;
struct kent *kent_root = NULL;
int kent_init(struct kent *kent, struct kent *parent)
static void kent_root_destroy(struct kent *kent)
{
int ret = 0;
/*
* this callback should never actually be executed in the first place
* because the kent root lives as long as the kernel is running but hey,
* it's not like our flash memory has a size limit or anything :)
*/
free(kent);
kent_root = NULL;
}
if (kent->operations == NULL)
return -EFAULT;
if (kent->operations->destroy == NULL)
static struct kent_ops kent_root_ops = {
.destroy = &kent_root_destroy,
};
int kent_root_init(void)
{
if (kent_root != NULL)
return -EEXIST;
kent_root = malloc(sizeof(*kent_root));
if (kent_root == NULL)
return -ENOMEM;
kent_root->parent = NULL;
kent_root->operations = &kent_root_ops;
atom_init(&kent_root->refcount);
kent_get(kent_root);
return 0;
}
int kent_init(struct kent *kent)
{
if (kent->parent == NULL || kent->operations == NULL)
return -EFAULT;
kent_get(kent->parent);
atom_init(&kent->refcount);
kent_get(kent);
if (parent == NULL)
parent = kent_root;
kent_get(parent);
kent->parent = parent;
return ret;
return 0;
}
void kent_get(struct kent *kent)
@ -38,16 +62,13 @@ void kent_get(struct kent *kent)
void kent_put(struct kent *kent)
{
struct kent *parent;
while (kent != NULL) {
parent = kent->parent;
if (atom_put(&kent->refcount) != 0)
break;
struct kent *parent = kent->parent;
if (atom_put(&kent->refcount) == 0) {
kent->operations->destroy(kent);
kent = parent;
if (parent != NULL)
kent_put(parent);
}
}

View file

@ -18,7 +18,7 @@ int serial_init(struct serial_device *dev, long int baud)
if (dev->id < 0)
return -1; /* invalid dev */
err = device_init(&dev->device, NULL);
err = device_init(&dev->device);
dev->baud = baud;