176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * core/fs/pxe/isr.c
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Stub invoked on return from real mode including from an interrupt.
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Interrupts are locked out on entry.
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "core.h"
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "thread.h"
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "pxe.h"
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/cpu.h>
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/io.h>
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern uint8_t pxe_irq_pending;
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern volatile uint8_t pxe_need_poll;
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic DECLARE_INIT_SEMAPHORE(pxe_receive_thread_sem, 0);
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic DECLARE_INIT_SEMAPHORE(pxe_poll_thread_sem, 0);
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct thread *pxe_thread, *poll_thread;
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef PXE_POLL_FORCE
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#  define PXE_POLL_FORCE 0
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef PXE_POLL_BY_MODEL
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#  define PXE_POLL_BY_MODEL 1
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: this *must* be called with interrupts enabled.
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old)
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    far_ptr_t *entry;
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned int vec;
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint8_t mask, mymask;
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint32_t now;
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    bool ok;
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (irq < 8)
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	vec = irq + 0x08;
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (irq < 16)
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	vec = (irq - 8) + 0x70;
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return false;
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cli();
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pxe_need_poll) {
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sti();
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return false;
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    entry = (far_ptr_t *)(vec << 2);
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *old = *entry;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    entry->ptr = (uint32_t)isr;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Enable this interrupt at the PIC level, just in case... */
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mymask = ~(1 << (irq & 7));
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (irq >= 8) {
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mask = inb(0x21);
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mask &= ~(1 << 2);	/* Enable cascade */
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outb(mask, 0x21);
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 	mask = inb(0xa1);
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mask &= mymask;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outb(mask, 0xa1);
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 	mask = inb(0x21);
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mask &= mymask;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	outb(mask, 0x21);
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sti();
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    now = jiffies();
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Some time to watch for stuck interrupts */
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (jiffies() - now < 4 && (ok = !pxe_need_poll))
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hlt();
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!ok)
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*entry = *old;		/* Restore the old vector */
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ddprintf("UNDI: IRQ %d(0x%02x): %04x:%04x -> %04x:%04x\n", irq, vec,
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   old->seg, old->offs, entry->seg, entry->offs);
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ok;
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old)
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    far_ptr_t *entry;
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned int vec;
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    bool rv;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!irq)
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return true;		/* Nothing to uninstall */
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (irq < 8)
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	vec = irq + 0x08;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (irq < 16)
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	vec = (irq - 8) + 0x70;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return false;
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cli();
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    entry = (far_ptr_t *)(vec << 2);
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (entry->ptr != (uint32_t)isr) {
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = false;
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	*entry = *old;
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = true;
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sti();
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv;
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pxe_poll_wakeups(void)
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static jiffies_t last_jiffies = 0;
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    jiffies_t now = jiffies();
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pxe_need_poll == 1) {
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If we need polling now, activate polling */
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pxe_need_poll = 3;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sem_up(&pxe_poll_thread_sem);
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (now != last_jiffies) {
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	last_jiffies = now;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	__thread_process_timeouts();
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pxe_irq_pending) {
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pxe_irq_pending = 0;
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sem_up(&pxe_receive_thread_sem);
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pxe_process_irq(void)
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static __lowmem t_PXENV_UNDI_ISR isr;
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uint16_t func = PXENV_UNDI_ISR_IN_PROCESS; /* First time */
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    bool done = false;
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (!done) {
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        memset(&isr, 0, sizeof isr);
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        isr.FuncFlag = func;
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        func = PXENV_UNDI_ISR_IN_GET_NEXT; /* Next time */
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        pxe_call(PXENV_UNDI_ISR, &isr);
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        switch (isr.FuncFlag) {
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        case PXENV_UNDI_ISR_OUT_DONE:
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    done = true;
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        case PXENV_UNDI_ISR_OUT_TRANSMIT:
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Transmit complete - nothing for us to do */
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        case PXENV_UNDI_ISR_OUT_RECEIVE:
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    undiif_input(&isr);
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        case PXENV_UNDI_ISR_OUT_BUSY:
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* ISR busy, this should not happen */
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    done = true;
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        default:
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Invalid return code, this should not happen */
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    done = true;
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pxe_receive_thread(void *dummy)
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)dummy;
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (;;) {
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sem_down(&pxe_receive_thread_sem, 0);
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pxe_process_irq();
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool pxe_isr_poll(void)
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static __lowmem t_PXENV_UNDI_ISR isr;
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pxe_call(PXENV_UNDI_ISR, &isr);
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return isr.FuncFlag == PXENV_UNDI_ISR_OUT_OURS;
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void pxe_poll_thread(void *dummy)
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)dummy;
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Block indefinitely unless activated */
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sem_down(&pxe_poll_thread_sem, 0);
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (;;) {
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cli();
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (pxe_receive_thread_sem.count < 0 && pxe_isr_poll())
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    sem_up(&pxe_receive_thread_sem);
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    __schedule();
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sti();
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cpu_relax();
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This does preparations and enables the PXE thread
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid pxe_init_isr(void)
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    start_idle_thread();
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sched_hook_func = pxe_poll_wakeups;
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Run the pxe receive thread at elevated priority, since the UNDI
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * stack is likely to have very limited memory available; therefore to
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * avoid packet loss we need to move it into memory that we ourselves
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * manage, as soon as possible.
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    core_pm_hook = __schedule;
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pxe_thread = start_thread("pxe receive", 16384, -20,
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			      pxe_receive_thread, NULL);
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Actually start the interrupt routine inside the UNDI stack
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid pxe_start_isr(void)
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int irq = pxe_undi_info.IntNumber;
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (irq == 2)
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	irq = 9;		/* IRQ 2 is really IRQ 9 */
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else if (irq > 15)
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	irq = 0;		/* Invalid IRQ */
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pxe_irq_vector = irq;
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (irq) {
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!install_irq_vector(irq, pxe_isr, &pxe_irq_chain))
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    irq = 0;		/* Install failed or stuck interrupt */
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    poll_thread = start_thread("pxe poll", 4096, POLL_THREAD_PRIORITY,
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			       pxe_poll_thread, NULL);
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!irq ||	!(pxe_undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ)) {
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dprintf("pxe_start_isr: forcing pxe_need_poll\n");
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (PXE_POLL_BY_MODEL) {
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dprintf("pxe_start_isr: trying poll by model\n");
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int hwad = ((int)MAC[0] << 16) + ((int)MAC[1] << 8) + MAC[2];
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dprintf("pxe_start_isr: got %06x %04x\n", hwad, pxe_undi_iface.ServiceFlags);
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if ((hwad == 0x000023ae) && (pxe_undi_iface.ServiceFlags == 0xdc1b) ||
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (hwad == 0x005c260a) && (pxe_undi_iface.ServiceFlags == 0xdc1b) ||
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    (hwad == 0x00180373) && (pxe_undi_iface.ServiceFlags == 0xdc1b)) {
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		dprintf("pxe_start_isr: forcing pxe_need_poll by model\n");
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint reset_pxe(void)
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static __lowmem struct s_PXENV_UNDI_CLOSE undi_close;
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    sched_hook_func = NULL;
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    core_pm_hook = core_pm_null_hook;
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    kill_thread(pxe_thread);
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&undi_close, 0, sizeof(undi_close));
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pxe_call(PXENV_UNDI_CLOSE, &undi_close);
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (undi_close.Status)
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("PXENV_UNDI_CLOSE failed: 0x%x\n", undi_close.Status);
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pxe_irq_vector)
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uninstall_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain);
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (poll_thread)
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	kill_thread(poll_thread);
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return undi_close.Status;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
299