Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull upstream #24

Merged
merged 3 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion kernel/arch/dreamcast/hardware/pvr/pvr_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ static uint32 pvr_mem_available_int(void) {
}

uint32 pvr_mem_available(void) {
CHECK_MEM_BASE;
if(!pvr_mem_base)
return 0;

return pvr_mem_available_int() +
(PVR_RAM_INT_TOP - (uint32)pvr_mem_base);
Expand Down
122 changes: 74 additions & 48 deletions kernel/arch/dreamcast/hardware/sq.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@
static mutex_t sq_mutex = RECURSIVE_MUTEX_INITIALIZER;

typedef struct sq_state {
uint8_t dest0;
uint8_t dest1;
mmu_token_t mmu_token;
uint32_t dest;
} sq_state_t;

#ifndef SQ_STATE_CACHE_SIZE
Expand All @@ -67,26 +65,33 @@ typedef struct sq_state {

static sq_state_t sq_state_cache[SQ_STATE_CACHE_SIZE] = {0};

void sq_lock(void *dest) {
uint32_t *sq_lock(void *dest) {
sq_state_t *new_state;
bool with_mmu;
uint32_t mask;

mutex_lock(&sq_mutex);

assert_msg(sq_mutex.count < SQ_STATE_CACHE_SIZE, "You've overrun the SQ_STATE_CACHE.");

new_state = &sq_state_cache[sq_mutex.count - 1];

/* Disable MMU, because SQs work differently when it's enabled, and we
* don't support it. */
new_state->mmu_token = mmu_disable();
new_state->dest = (uint32_t)dest;

new_state->dest0 = new_state->dest1 = QACR_EXTERN_BITS(dest);
with_mmu = mmu_enabled();
mask = with_mmu ? 0x000fffe0 : 0x03ffffe0;

SET_QACR_REGS_INNER(new_state->dest0, new_state->dest1);
if (with_mmu)
mmu_set_sq_addr(dest);
else
SET_QACR_REGS(dest, dest);

return (uint32_t *)(MEM_AREA_SQ_BASE | ((uintptr_t)dest & mask));
}

void sq_unlock(void) {
sq_state_t *tmp_state;
bool with_mmu;

if(sq_mutex.count == 0) {
dbglog(DBG_WARNING, "sq_unlock: Called without any lock\n");
Expand All @@ -95,13 +100,15 @@ void sq_unlock(void) {

tmp_state = &sq_state_cache[sq_mutex.count - 1];

/* Restore the mmu state that we had started with */
mmu_restore(tmp_state->mmu_token);

/* If we aren't the last entry, set the regs back where they belong */
if(sq_mutex.count - 1) {
tmp_state = &sq_state_cache[sq_mutex.count - 2];
SET_QACR_REGS_INNER(tmp_state->dest0, tmp_state->dest1);
with_mmu = mmu_enabled();

if (with_mmu)
mmu_set_sq_addr((void *)tmp_state->dest);
else
SET_QACR_REGS(tmp_state->dest, tmp_state->dest);
}

mutex_unlock(&sq_mutex);
Expand All @@ -115,38 +122,48 @@ void sq_wait(void) {

/* Copies n bytes from src to dest, dest must be 32-byte aligned */
__attribute__((noinline)) void *sq_cpy(void *dest, const void *src, size_t n) {
uint32_t *d = SQ_MASK_DEST(dest);
const uint32_t *s = src;
void *curr_dest = dest;
uint32_t *d;
size_t nb;

/* Fill/write queues as many times necessary */
n >>= 5;

/* Exit early if we dont have enough data to copy */
if(n == 0)
return dest;

sq_lock(dest);

/* If src is not 8-byte aligned, slow path */
if ((uintptr_t)src & 7) {
while(n--) {
dcache_pref_block(s + 8); /* Prefetch 32 bytes for next loop */
d[0] = *(s++);
d[1] = *(s++);
d[2] = *(s++);
d[3] = *(s++);
d[4] = *(s++);
d[5] = *(s++);
d[6] = *(s++);
d[7] = *(s++);
sq_flush(d);
d += 8;
while (n > 0) {
/* Transfer maximum 1 MiB at once. This is because when using the
* MMU the SQ area is 2 MiB, and the destination address may
* not be on a page boundary. */
nb = n > 0x8000 ? 0x8000 : n;

d = sq_lock(curr_dest);

curr_dest += nb * 32;
n -= nb;

/* If src is not 8-byte aligned, slow path */
if ((uintptr_t)src & 7) {
while(nb--) {
dcache_pref_block(s + 8); /* Prefetch 32 bytes for next loop */
d[0] = *(s++);
d[1] = *(s++);
d[2] = *(s++);
d[3] = *(s++);
d[4] = *(s++);
d[5] = *(s++);
d[6] = *(s++);
d[7] = *(s++);
sq_flush(d);
d += 8;
}
} else { /* If src is 8-byte aligned, fast path */
sq_fast_cpy(d, s, nb);
s += nb * 32;
}
} else { /* If src is 8-byte aligned, fast path */
sq_fast_cpy(d, s, n);

sq_unlock();
}

sq_unlock();
return dest;
}

Expand All @@ -170,25 +187,34 @@ void *sq_set16(void *dest, uint32_t c, size_t n) {

/* Fills n bytes at dest with int c, dest must be 32-byte aligned */
void *sq_set32(void *dest, uint32_t c, size_t n) {
uint32_t *d = SQ_MASK_DEST(dest);
void *curr_dest = dest;
uint32_t *d;
size_t nb;

/* Write them as many times necessary */
n >>= 5;

/* Exit early if we dont have enough data to set */
if(n == 0)
return dest;
while (n > 0) {
/* Transfer maximum 1 MiB at once. This is because when using the
* MMU the SQ area is 2 MiB, and the destination address may
* not be on a page boundary. */
nb = n > 0x8000 ? 0x8000 : n;

sq_lock(dest);
d = sq_lock(curr_dest);

curr_dest += nb * 32;
n -= nb;

while(nb--) {
/* Fill both store queues with c */
d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = c;
sq_flush(d);
d += 8;
}

while(n--) {
/* Fill both store queues with c */
d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = c;
sq_flush(d);
d += 8;
sq_unlock();
}

sq_unlock();
return dest;
}

Expand Down
22 changes: 10 additions & 12 deletions kernel/arch/dreamcast/include/arch/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#include <sys/cdefs.h>
__BEGIN_DECLS

#include <stdbool.h>

#include <arch/types.h>
#include <sys/uio.h>

Expand Down Expand Up @@ -195,9 +197,6 @@ typedef struct mmucontext {
to do so.
*/
extern mmucontext_t *mmu_cxt_current;

struct mmu_token;
typedef struct mmu_token *mmu_token_t;
/** \endcond */

/** \brief Set the "current" page tables for TLB handling.
Expand Down Expand Up @@ -373,19 +372,18 @@ void mmu_shutdown(void);
*/
void mmu_reset_itlb(void);

/** \brief Temporarily disable MMU address translation.
/** \brief Check if MMU translation is enabled.
\ingroup mmu

\return An opaque token to be passed to mmu_restore()
\return True if MMU translation is enabled, false otherwise.
*/
mmu_token_t mmu_disable(void);
bool mmu_enabled(void);

/** \brief Restore MMU address translation.
\ingroup mmu

\param token The opaque token obtained from mmu_disable()
*/
void mmu_restore(mmu_token_t token);
/** \brief Reset the base target address for store queues.
* \ingroup mmu
*
* \param addr The base address to reset to */
void mmu_set_sq_addr(void *addr);

__END_DECLS

Expand Down
5 changes: 4 additions & 1 deletion kernel/arch/dreamcast/include/dc/sq.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,12 @@ __BEGIN_DECLS
however, it must be called manually when driving the SQs directly from outside
of this API.

\param dest The destination address.
\return The translated address that can be directly written to.

\sa sq_unlock()
*/
void sq_lock(void *dest);
uint32_t *sq_lock(void *dest);

/** \brief Unlock Store Queues
\ingroup store_queues
Expand Down
29 changes: 18 additions & 11 deletions kernel/arch/dreamcast/kernel/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,9 +738,15 @@ int mmu_init(void) {
irq_set_handler(EXC_DTLB_PV_WRITE, dtlb_pv_write, NULL);
irq_set_handler(EXC_INITIAL_PAGE_WRITE, initial_page_write, NULL);

/* Turn on MMU */
/* URB=0x3f, URC=0, SQMD=1, SV=0, TI=1, AT=1 */
SET_MMUCR(0x3f, 0, 1, 0, 1, 1);
/* Reserve TLB entries 62-63 for SQ translation. Register them as read-write
* (since there's no write-only flag) with a 1 MiB page. */
SET_MMUCR(0x3e, 0x3e, 1, 0, 1, 1);
mmu_ldtlb(0, 0xe0000000, 0, 3, 1, 0, 0, 0, 0);
SET_MMUCR(0x3f, 0x3f, 1, 0, 1, 1);
mmu_ldtlb(0, 0xe0100000, 0, 3, 1, 0, 0, 0, 0);

/* Set URB to 0x3d to not overwrite the SQ config, reset URC, enable MMU */
SET_MMUCR(0x3d, 0, 1, 0, 1, 1);

/* Clear the ITLB */
mmu_reset_itlb();
Expand All @@ -767,14 +773,15 @@ void mmu_shutdown(void) {
irq_set_handler(EXC_INITIAL_PAGE_WRITE, NULL, NULL);
}

mmu_token_t mmu_disable(void) {
mmu_token_t token = (mmu_token_t)*mmucr;

*mmucr &= ~0x1;

return token;
bool mmu_enabled(void) {
return *mmucr & 0x1;
}

void mmu_restore(mmu_token_t token) {
*mmucr = (uint32)token;
void mmu_set_sq_addr(void *addr) {
uint32_t ppn1 = (uint32_t)addr & 0x1ff00000;
uint32_t ppn2 = ppn1 + 0x00100000;

/* Reset the base target address for the SQs */
*(uint32_t *)(MEM_AREA_UTLB_DATA_ARRAY1_BASE + (0x3e << 8)) = ppn1 | 0x1fc;
*(uint32_t *)(MEM_AREA_UTLB_DATA_ARRAY1_BASE + (0x3f << 8)) = ppn2 | 0x1fc;
}
3 changes: 2 additions & 1 deletion kernel/arch/dreamcast/sound/snd_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ uint32 snd_mem_available(void) {
snd_block_t *e;
size_t largest = 0;

assert_msg(initted, "Use of snd_mem_available before snd_mem_init");
if(!initted)
return 0;

if(irq_inside_int()) {
if(!spinlock_trylock(&snd_mem_mutex)) {
Expand Down