diff options
author | se <se@FreeBSD.org> | 1995-03-21 23:06:07 +0000 |
---|---|---|
committer | se <se@FreeBSD.org> | 1995-03-21 23:06:07 +0000 |
commit | 0cdd391c0583fc081ed2d75fb9f3baaa599de103 (patch) | |
tree | e93fa1f23f13abe8e75be2b0429e887dc8e1a5ba /sys/i386/pci/pci_pir.c | |
parent | 6e667246cd96976e175eec9db61940c42681a155 (diff) | |
download | FreeBSD-src-0cdd391c0583fc081ed2d75fb9f3baaa599de103.zip FreeBSD-src-0cdd391c0583fc081ed2d75fb9f3baaa599de103.tar.gz |
New ISA specific PCI code.
Supports shared PCI interrupts.
Submitted by: Wolfgang Stanglmeier <wolf@kintaro.cologne.de>
Diffstat (limited to 'sys/i386/pci/pci_pir.c')
-rw-r--r-- | sys/i386/pci/pci_pir.c | 356 |
1 files changed, 209 insertions, 147 deletions
diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c index f1cdd1e..b1fd217 100644 --- a/sys/i386/pci/pci_pir.c +++ b/sys/i386/pci/pci_pir.c @@ -1,6 +1,6 @@ /************************************************************************** ** -** $Id: pcibus.c,v 1.3 1995/02/25 17:51:18 se Exp $ +** $Id: pcibus.c,v 1.4 1995/02/26 05:14:51 bde Exp $ ** ** pci bus subroutines for i386 architecture. ** @@ -35,15 +35,7 @@ *************************************************************************** */ -#ifndef __FreeBSD2__ -#if __FreeBSD__ >= 2 -#define __FreeBSD2__ -#endif -#endif - -#ifdef __FreeBSD2__ -#define HAS_CPUFUNC_H -#endif +#define __PCIBUS_C___ "pl4 95/03/21" #include <sys/param.h> #include <sys/systm.h> @@ -57,23 +49,89 @@ #include <pci/pcireg.h> #include <pci/pcibus.h> -static char pci_mode; - +extern int printf(); + +#ifdef DENTARO + +#define SFAKE (32) + +static void +dec21050 (u_int*reg) { + reg[0] = 0x00011011; + reg[1]&= 0x000001e7; + reg[2] = 0x06040001; + reg[3]&= 0x0000f8ff; + reg[3]|= 0x000100ff; + reg[4] = 0x00000000; + reg[5] = 0x00000000; + reg[6]&= 0xf8ffffff; + reg[7]&= 0x0000f0f0; /* io-limit */ + reg[8]&= 0xfff0fff0; /* mem-limit, non prefatchable */ + reg[9]&= 0xfff0fff0; /* mem-limit, prefetchable memory */ + reg[10] = 0x00000000; + reg[11] = 0x00000000; + reg[12] = 0x00000000; + reg[13] = 0x00000000; + reg[14] = 0x00000000; + reg[15]&= 0x00ef0000; +} + +static void +dec21140 (u_int*reg) { + reg[0] = 0x00091011u; + reg[4]&= 0xfffffffdu; + reg[4]|= 0x00000001u; + reg[5]&= 0xffffff00u; +} + +struct fake { + u_int tag; + void (*proc)(u_int*); +}; + +struct fake faketable [] = { +{ 0xc70000f1, dec21050 }, +{ 0xc00001f1, dec21140 }, +{ 0xc40001f1, dec21140 }, +{ 0xc80001f1, dec21140 }, +{ 0xcc0001f1, dec21140 }, +}; + +#define NFAKE (sizeof faketable / sizeof (struct fake)) + +static u_int fakedata[NFAKE * SFAKE]; + +u_int* findfake (pcici_t tag) +{ + u_int *p; + int i; + for (i=0; i<NFAKE; i++) + if (faketable[i].tag == tag.tag) + break; + + if (i>=NFAKE) + return (0); + p = &fakedata[i*SFAKE]; + (*faketable[i].proc)(p); + return (p); +} +#endif /*DENTARO*/ + /*----------------------------------------------------------------- ** ** The following functions are provided by the pci bios. ** They are used only by the pci configuration. ** -** pcibus_mode(): +** pcibus_setup(): ** Probes for a pci system. -** Returns 1 or 2 for pci configuration mechanism. -** Returns 0 if no pci system. +** Sets pci_maxdevice and pci_mechanism. ** ** pcibus_tag(): -** Gets a handle for accessing the pci configuration -** space. -** This handle is given to the mapping functions (see -** above) or to the read/write functions. +** Creates a handle for pci configuration space access. +** This handle is given to the read/write functions. +** +** pcibus_ftag(): +** Creates a modified handle. ** ** pcibus_read(): ** Read a long word from the pci configuration space. @@ -93,12 +151,15 @@ static char pci_mode; **----------------------------------------------------------------- */ -static int -pcibus_mode (void); +static void +pcibus_setup (void); static pcici_t pcibus_tag (u_char bus, u_char device, u_char func); +static pcici_t +pcibus_ftag (pcici_t tag, u_char func); + static u_long pcibus_read (pcici_t tag, u_long reg); @@ -106,15 +167,29 @@ static void pcibus_write (pcici_t tag, u_long reg, u_long data); static int -pcibus_regint (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr); +pcibus_ihandler_attach (int irq, void(*ihandler)(), int arg, unsigned* maskp); + +static int +pcibus_ihandler_detach (int irq, void(*handler)()); + +static int +pcibus_imask_include (int irq, unsigned* maskptr); + +static int +pcibus_imask_exclude (int irq, unsigned* maskptr); struct pcibus i386pci = { "pci", - pcibus_mode, + pcibus_setup, pcibus_tag, + pcibus_ftag, pcibus_read, pcibus_write, - pcibus_regint, + ICU_LEN, + pcibus_ihandler_attach, + pcibus_ihandler_detach, + pcibus_imask_include, + pcibus_imask_exclude, }; /* @@ -122,41 +197,7 @@ struct pcibus i386pci = { */ DATA_SET (pcibus_set, i386pci); - -/*-------------------------------------------------------------------- -** -** Port access -** -**-------------------------------------------------------------------- -*/ - -#ifndef HAS_CPUFUNC_H -#undef inl -#define inl(port) \ -({ u_long data; \ - __asm __volatile("inl %1, %0": "=a" (data): "d" ((u_short)(port))); \ - data; }) - - -#undef outl -#define outl(port, data) \ -{__asm __volatile("outl %0, %1"::"a" ((u_long)(data)), "d" ((u_short)(port)));} - - -#undef inb -#define inb(port) \ -({ u_char data; \ - __asm __volatile("inb %1, %0": "=a" (data): "d" ((u_short)(port))); \ - data; }) - - -#undef outb -#define outb(port, data) \ -{__asm __volatile("outb %0, %1"::"a" ((u_char)(data)), "d" ((u_short)(port)));} - -#endif /* HAS_CPUFUNC_H */ - /*-------------------------------------------------------------------- ** ** Determine configuration mode @@ -174,13 +215,9 @@ DATA_SET (pcibus_set, i386pci); #define CONF2_FORWARD_PORT 0x0cfa -static int -pcibus_mode (void) +static void +pcibus_setup (void) { -#ifdef PCI_CONF_MODE - pci_mode = PCI_CONF_MODE; - return (PCI_CONF_MODE) -#else /* PCI_CONF_MODE */ u_long result, oldval; /*--------------------------------------- @@ -191,8 +228,8 @@ pcibus_mode (void) outb (CONF2_ENABLE_PORT, 0); outb (CONF2_FORWARD_PORT, 0); if (!inb (CONF2_ENABLE_PORT) && !inb (CONF2_FORWARD_PORT)) { - pci_mode = 2; - return (2); + pci_mechanism = 2; + pci_maxdevice = 16; }; /*--------------------------------------- @@ -206,18 +243,16 @@ pcibus_mode (void) outl (CONF1_ADDR_PORT, oldval); if (result == CONF1_ENABLE) { - pci_mode = 1; - return (1); + pci_mechanism = 1; + pci_maxdevice = 32; }; /*--------------------------------------- ** No PCI bus available. **--------------------------------------- */ - return (0); -#endif /* PCI_CONF_MODE */ } - + /*-------------------------------------------------------------------- ** ** Build a pcitag from bus, device and function number @@ -234,7 +269,7 @@ pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) if (device >= 32) return tag; if (func >= 8) return tag; - switch (pci_mode) { + switch (pci_mechanism) { case 1: tag.cfg1 = CONF1_ENABLE @@ -251,7 +286,23 @@ pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) }; return tag; } - + +static pcici_t +pcibus_ftag (pcici_t tag, u_char func) +{ + switch (pci_mechanism) { + + case 1: + tag.cfg1 &= ~0x700ul; + tag.cfg1 |= (((u_long) func) << 8ul); + break; + case 2: + tag.cfg2.enable = 0xf1 | (func << 1ul); + break; + }; + return tag; +} + /*-------------------------------------------------------------------- ** ** Read register from configuration space. @@ -259,15 +310,25 @@ pcibus_tag (unsigned char bus, unsigned char device, unsigned char func) **-------------------------------------------------------------------- */ - static u_long pcibus_read (pcici_t tag, u_long reg) { u_long addr, data = 0; +#ifdef DENTARO + u_int*p = findfake(tag); + if (p) { +#if 0 + printf ("fake conf_read (tag=%x reg=%d val=%08x).\n", + tag.tag, (unsigned) reg, (unsigned) p[reg/4]); +#endif + return (p[reg/4]); + } +#endif + if (!tag.cfg1) return (0xfffffffful); - switch (pci_mode) { + switch (pci_mechanism) { case 1: addr = tag.cfg1 | (reg & 0xfc); @@ -300,7 +361,7 @@ pcibus_read (pcici_t tag, u_long reg) return (data); } - + /*-------------------------------------------------------------------- ** ** Write register into configuration space. @@ -308,15 +369,26 @@ pcibus_read (pcici_t tag, u_long reg) **-------------------------------------------------------------------- */ - static void pcibus_write (pcici_t tag, u_long reg, u_long data) { u_long addr; +#ifdef DENTARO + u_int*p = findfake(tag); + if (p) { +#if 0 + printf ("fake conf_write (tag=%x reg=%d val=%08x).\n", + tag.tag, (unsigned) reg, (unsigned) data); +#endif + p[reg/4]=data; + return; + } +#endif + if (!tag.cfg1) return; - switch (pci_mode) { + switch (pci_mechanism) { case 1: addr = tag.cfg1 | (reg & 0xfc); @@ -345,7 +417,7 @@ pcibus_write (pcici_t tag, u_long reg, u_long data) break; }; } - + /*----------------------------------------------------------------------- ** ** Register an interupt handler for a pci device. @@ -353,87 +425,77 @@ pcibus_write (pcici_t tag, u_long reg, u_long data) **----------------------------------------------------------------------- */ -#ifndef __FreeBSD2__ -/* - * Type of the first (asm) part of an interrupt handler. - */ -typedef void inthand_t __P((u_int cs, u_int ef, u_int esp, u_int ss)); - -/* - * Usual type of the second (C) part of an interrupt handler. Some bogus - * ones need the arg to be the interrupt frame (and not a copy of it, which - * is all that is possible in C). - */ -typedef void inthand2_t __P((int unit)); +static int +pcibus_ihandler_attach (int irq, void(*func)(), int arg, unsigned * maskptr) +{ + int result; + result = register_intr( + irq, /* isa irq */ + 0, /* deviced?? */ + 0, /* flags? */ + (inthand2_t*) func, /* handler */ + maskptr, /* mask pointer */ + arg); /* handler arg */ + + if (result) { + printf ("@@@ pcibus_ihandler_attach: result=%d\n", result); + return (result); + }; + update_intr_masks(); -/* -** XXX @FreeBSD2@ -** -** Unfortunately, the mptr argument is _no_ pointer in 2.0 FreeBSD. -** We would prefer a pointer because it enables us to install -** new interrupt handlers at any time. -** (This is just going to be changed ... <se> :) -** In 2.0 FreeBSD later installed interrupt handlers may change -** the xyz_imask, but this would not be recognized by handlers -** which are installed before. -*/ + INTREN ((1ul<<irq)); + return (0); +} static int -register_intr __P((int intr, int device_id, unsigned int flags, - inthand2_t *handler, unsigned int * mptr, int unit)); -extern unsigned intr_mask[ICU_LEN]; +pcibus_ihandler_detach (int irq, void(*func)()) +{ + int result; -#endif /* !__FreeBSD2__ */ -static unsigned int pci_int_mask [16]; + INTRDIS ((1ul<<irq)); -int pcibus_regint (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr) + result = unregister_intr (irq, (inthand2_t*) func); + + if (result) + printf ("@@@ pcibus_ihandler_detach: result=%d\n", result); + + update_intr_masks(); + + return (result); +} + +static int +pcibus_imask_include (int irq, unsigned* maskptr) { - int irq; - unsigned mask, oldmask; + unsigned mask; - irq = PCI_INTERRUPT_LINE_EXTRACT( - pci_conf_read (tag, PCI_INTERRUPT_REG)); + if (!maskptr) return (0); mask = 1ul << irq; - if (!maskptr) - maskptr = &pci_int_mask[irq]; - oldmask = *maskptr; + if (*maskptr & mask) + return (-1); INTRMASK (*maskptr, mask); + update_intr_masks(); - register_intr( - irq, /* isa irq */ - 0, /* deviced?? */ - 0, /* flags? */ - (inthand2_t*) func, /* handler */ - maskptr, /* mask pointer */ - (int) arg); /* handler arg */ - -#ifdef __FreeBSD2__ - /* - ** XXX See comment at beginning of file. - ** - ** Have to update all the interrupt masks ... Grrrrr!!! - */ - { - unsigned * mp = &intr_mask[0]; - /* - ** update the isa interrupt masks. - */ - for (mp=&intr_mask[0]; mp<&intr_mask[ICU_LEN]; mp++) - if ((~*mp & oldmask)==0) - *mp |= mask; - /* - ** update the pci interrupt masks. - */ - for (mp=&pci_int_mask[0]; mp<&pci_int_mask[16]; mp++) - if ((~*mp & oldmask)==0) - *mp |= mask; - }; -#endif + return (0); +} - INTREN (mask); +static int +pcibus_imask_exclude (int irq, unsigned* maskptr) +{ + unsigned mask; - return (1); + if (!maskptr) return (0); + + mask = 1ul << irq; + + if (! (*maskptr & mask)) + return (-1); + + *maskptr &= ~mask; + update_intr_masks(); + + return (0); } |