#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/sema.h>
#include <machine/bus.h>
#include <machine/atomic.h>
#include "apple_bce.h"
#include "apple_bce_mailbox.h"
int
bce_mailbox_init(struct bce_mailbox *mb, struct resource *reg)
{
mb->reg = reg;
mb->status = 0;
sema_init(&mb->mb_cmpl, 0, "bce_mb");
mb->mb_result = 0;
mb->initialized = 1;
return (0);
}
void
bce_mailbox_destroy(struct bce_mailbox *mb)
{
if (mb->initialized) {
sema_destroy(&mb->mb_cmpl);
mb->initialized = 0;
}
}
int
bce_mailbox_send(struct bce_mailbox *mb, uint64_t msg, uint64_t *recv,
unsigned int timeout_ms)
{
int old;
old = atomic_cmpset_int(&mb->status, 0, 1);
if (old == 0)
return (EBUSY);
bus_write_4(mb->reg, BCE_REG_MBOX_OUT, (uint32_t)msg);
bus_write_4(mb->reg, BCE_REG_MBOX_OUT + 4, (uint32_t)(msg >> 32));
bus_write_4(mb->reg, BCE_REG_MBOX_OUT + 8, 0);
bus_write_4(mb->reg, BCE_REG_MBOX_OUT + 12, 0);
if (recv == NULL) {
atomic_store_int(&mb->status, 0);
return (0);
}
if (sema_timedwait(&mb->mb_cmpl, hz * timeout_ms / 1000) != 0) {
atomic_store_int(&mb->status, 0);
return (ETIMEDOUT);
}
if (atomic_load_int(&mb->status) != 2) {
atomic_store_int(&mb->status, 0);
return (ETIMEDOUT);
}
if (recv != NULL)
*recv = mb->mb_result;
atomic_store_int(&mb->status, 0);
return (0);
}
int
bce_mailbox_handle_interrupt(struct bce_mailbox *mb)
{
uint32_t res, lo, hi;
int count;
res = bus_read_4(mb->reg, BCE_REG_MBOX_REPLY_CTR);
count = (res >> 20) & 0xf;
if (count == 0)
return (ENOMSG);
while (count-- > 0) {
lo = bus_read_4(mb->reg, BCE_REG_MBOX_REPLY);
hi = bus_read_4(mb->reg, BCE_REG_MBOX_REPLY + 4);
bus_read_4(mb->reg, BCE_REG_MBOX_REPLY + 8);
bus_read_4(mb->reg, BCE_REG_MBOX_REPLY + 12);
mb->mb_result = ((uint64_t)hi << 32) | lo;
}
if (atomic_load_int(&mb->status) == 1) {
atomic_store_int(&mb->status, 2);
sema_post(&mb->mb_cmpl);
}
return (0);
}