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:
parent
5fa7639ce8
commit
4349420217
8 changed files with 100 additions and 48 deletions
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
11
kernel/dma.c
11
kernel/dma.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue