Created: Jan 2000 by Philip Homburg <philip@cs.vu.nl>
*/
-#include <assert.h>
-#include <machine/pci.h>
-#include <machine/vm.h>
-#include <machine/vmparam.h>
-#include <minix/com.h>
-#include <minix/ds.h>
-#include <minix/syslib.h>
+#include <minix/driver.h>
+
+#include <minix/acpi.h>
#include <minix/param.h>
+#include <minix/ds.h>
+#include <minix/rs.h>
-#include "pci.h"
+#include <machine/pci.h>
#include <machine/pci_amd.h>
#include <machine/pci_intel.h>
#include <machine/pci_sis.h>
#include <machine/pci_via.h>
-#if __minix_vmd
-#include "config.h"
-#endif
-
-#if !__minix_vmd
-#define irq_mode_pci(irq) ((void)0)
-#endif
+#include <machine/vmparam.h>
#include <stdlib.h>
#include <stdio.h>
-#include <minix/sysutil.h>
-#include <minix/acpi.h>
+
+#include "pci.h"
+
+#define irq_mode_pci(irq) ((void)0)
#define PBT_INTEL_HOST 1
#define PBT_PCIBRIDGE 2
#define BAM_NR 6 /* Number of base-address registers */
-int debug= 0;
+struct pci_acl pci_acl[NR_DRIVERS];
static struct pcibus
{
int pd_bar_nr;
} pcidev[NR_PCIDEV];
-EXTERN struct pci_acl pci_acl[NR_DRIVERS];
-
/* pb_flags */
#define PBF_IO 1 /* I/O else memory */
#define PBF_INCOMPLETE 2 /* not allocated */
static int nr_pcidev= 0;
-static void pci_intel_init(void);
-static void probe_bus(int busind);
-static int is_duplicate(u8_t busnr, u8_t dev, u8_t func);
-static void record_irq(int devind);
-static void record_bars_normal(int devind);
-static void record_bars_bridge(int devind);
-static void record_bars_cardbus(int devind);
-static void record_bars(int devind, int last_reg);
-static int record_bar(int devind, int bar_nr, int last);
-static void complete_bridges(void);
-static void complete_bars(void);
-static void update_bridge4dev_io(int devind, u32_t io_base, u32_t
- io_size);
-static int get_freebus(void);
-static int do_isabridge(int busind);
-static void do_pcibridge(int busind);
-static int get_busind(int busnr);
-static int do_piix(int devind);
-static int do_amd_isabr(int devind);
-static int do_sis_isabr(int devind);
-static int do_via_isabr(int devind);
-#if 0
-static void report_vga(int devind);
-#endif
-static char *pci_vid_name(u16_t vid);
-static char *pci_baseclass_name(u8_t baseclass);
-static char *pci_subclass_name(u8_t baseclass, u8_t subclass, u8_t
- infclass);
-static void ntostr(unsigned n, char **str, const char *end);
-
-static u8_t pci_attr_r8_u(int devind, int port);
-static u32_t pci_attr_r32_u(int devind, int port);
-
-static u16_t pci_attr_rsts(int devind);
-static void pci_attr_wsts(int devind, u16_t value);
-static u16_t pcibr_std_rsts(int busind);
-static void pcibr_std_wsts(int busind, u16_t value);
-static u16_t pcibr_cb_rsts(int busind);
-static void pcibr_cb_wsts(int busind, u16_t value);
-static u16_t pcibr_via_rsts(int busind);
-static void pcibr_via_wsts(int busind, u16_t value);
-static u8_t pcii_rreg8(int busind, int devind, int port);
-static u16_t pcii_rreg16(int busind, int devind, int port);
-static u32_t pcii_rreg32(int busind, int devind, int port);
-static void pcii_wreg8(int busind, int devind, int port, u8_t value);
-static void pcii_wreg16(int busind, int devind, int port, u16_t value);
-static void pcii_wreg32(int busind, int devind, int port, u32_t value);
-static u16_t pcii_rsts(int busind);
-static void pcii_wsts(int busind, u16_t value);
-static void print_capabilities(int devind);
-static int visible(struct rs_pci *aclp, int devind);
-static void print_hyper_cap(int devind, u8_t capptr);
-
static struct machine machine;
static endpoint_t acpi_ep;
-/*===========================================================================*
- * sef_cb_init_fresh *
- *===========================================================================*/
-int sef_cb_init_fresh(int type, sef_init_info_t *info)
-{
-/* Initialize the pci driver. */
- long v;
- int i, r;
- struct rprocpub rprocpub[NR_BOOT_PROCS];
-
- v= 0;
- env_parse("pci_debug", "d", 0, &v, 0, 1);
- debug= v;
-
- if (sys_getmachine(&machine)) {
- printf("PCI: no machine\n");
- return ENODEV;
- }
- if (machine.apic_enabled &&
- ds_retrieve_label_endpt("acpi", &acpi_ep) != OK) {
- panic("PCI: Cannot use APIC mode without ACPI!\n");
- }
-
- /* Only Intel (compatible) PCI controllers are supported at the
- * moment.
- */
- pci_intel_init();
-
- /* Map all the services in the boot image. */
- if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
- (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) {
- panic("sys_safecopyfrom failed: %d", r);
- }
- for(i=0;i < NR_BOOT_PROCS;i++) {
- if(rprocpub[i].in_use) {
- if((r = map_service(&rprocpub[i])) != OK) {
- panic("unable to map service: %d", r);
- }
- }
- }
-
- return(OK);
-}
-
-/*===========================================================================*
- * map_service *
- *===========================================================================*/
-int map_service(rpub)
-struct rprocpub *rpub;
-{
-/* Map a new service by registering a new acl entry if required. */
- int i;
-
- /* Stop right now if no pci device or class is found. */
- if(rpub->pci_acl.rsp_nr_device == 0
- && rpub->pci_acl.rsp_nr_class == 0) {
- return(OK);
- }
-
- /* Find a free acl slot. */
- for (i= 0; i<NR_DRIVERS; i++)
- {
- if (!pci_acl[i].inuse)
- break;
- }
- if (i >= NR_DRIVERS)
- {
- printf("PCI: map_service: table is full\n");
- return ENOMEM;
- }
-
- /* Initialize acl slot. */
- pci_acl[i].inuse = 1;
- pci_acl[i].acl = rpub->pci_acl;
-
- return(OK);
-}
-
/*===========================================================================*
* helper functions for I/O *
*===========================================================================*/
-unsigned pci_inb(u16_t port) {
+static unsigned
+pci_inb(u16_t port) {
u32_t value;
int s;
if ((s=sys_inb(port, &value)) !=OK)
printf("PCI: warning, sys_inb failed: %d\n", s);
return value;
}
-unsigned pci_inw(u16_t port) {
+
+static unsigned
+pci_inw(u16_t port) {
u32_t value;
int s;
if ((s=sys_inw(port, &value)) !=OK)
printf("PCI: warning, sys_inw failed: %d\n", s);
return value;
}
-unsigned pci_inl(u16_t port) {
+
+static unsigned
+pci_inl(u16_t port) {
u32_t value;
int s;
if ((s=sys_inl(port, &value)) !=OK)
printf("PCI: warning, sys_inl failed: %d\n", s);
return value;
}
-void pci_outb(u16_t port, u8_t value) {
+
+static void
+pci_outb(u16_t port, u8_t value) {
int s;
if ((s=sys_outb(port, value)) !=OK)
printf("PCI: warning, sys_outb failed: %d\n", s);
}
-void pci_outw(u16_t port, u16_t value) {
+
+static void
+pci_outw(u16_t port, u16_t value) {
int s;
if ((s=sys_outw(port, value)) !=OK)
printf("PCI: warning, sys_outw failed: %d\n", s);
}
-void pci_outl(u16_t port, u32_t value) {
+
+static void
+pci_outl(u16_t port, u32_t value) {
int s;
if ((s=sys_outl(port, value)) !=OK)
printf("PCI: warning, sys_outl failed: %d\n", s);
}
-/*===========================================================================*
- * pci_find_dev *
- *===========================================================================*/
-int pci_find_dev(u8_t bus, u8_t dev, u8_t func, int *devindp)
+static u8_t
+pcii_rreg8(int busind, int devind, int port)
{
- int devind;
+ u8_t v;
+ int s;
- for (devind= 0; devind < nr_pcidev; devind++)
- {
- if (pcidev[devind].pd_busnr == bus &&
- pcidev[devind].pd_dev == dev &&
- pcidev[devind].pd_func == func)
- {
- break;
- }
- }
- if (devind >= nr_pcidev)
- return 0;
+ v= PCII_RREG8_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
#if 0
- if (pcidev[devind].pd_inuse)
- return 0;
+ printf("pcii_rreg8(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
+ busind, devind, port,
+ pcibus[busind].pb_bus, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func, v);
#endif
- *devindp= devind;
- return 1;
+ return v;
}
-/*===========================================================================*
- * pci_first_dev_a *
- *===========================================================================*/
-int pci_first_dev_a(
- struct rs_pci *aclp,
- int *devindp,
- u16_t *vidp,
- u16_t *didp
-)
+static u16_t
+pcii_rreg16(int busind, int devind, int port)
{
- int devind;
+ u16_t v;
+ int s;
- for (devind= 0; devind < nr_pcidev; devind++)
- {
+ v= PCII_RREG16_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
#if 0
- if (pcidev[devind].pd_inuse)
- continue;
+ printf("pcii_rreg16(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
+ busind, devind, port,
+ pcibus[busind].pb_bus, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func, v);
#endif
- if (!visible(aclp, devind))
- continue;
- break;
- }
- if (devind >= nr_pcidev)
- return 0;
- *devindp= devind;
- *vidp= pcidev[devind].pd_vid;
- *didp= pcidev[devind].pd_did;
- return 1;
+ return v;
}
-/*===========================================================================*
- * pci_next_dev *
- *===========================================================================*/
-int pci_next_dev_a(
- struct rs_pci *aclp,
- int *devindp,
- u16_t *vidp,
- u16_t *didp
-)
+static u32_t
+pcii_rreg32(int busind, int devind, int port)
{
- int devind;
+ u32_t v;
+ int s;
- for (devind= *devindp+1; devind < nr_pcidev; devind++)
- {
+ v= PCII_RREG32_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
#if 0
- if (pcidev[devind].pd_inuse)
- continue;
+ printf("pcii_rreg32(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
+ busind, devind, port,
+ pcibus[busind].pb_bus, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func, v);
#endif
- if (!visible(aclp, devind))
- continue;
- break;
- }
- if (devind >= nr_pcidev)
- return 0;
- *devindp= devind;
- *vidp= pcidev[devind].pd_vid;
- *didp= pcidev[devind].pd_did;
- return 1;
+ return v;
+}
+
+static void
+pcii_wreg8(int busind, int devind, int port, u8_t value)
+{
+ int s;
+#if 0
+ printf("pcii_wreg8(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
+ busind, devind, port, value,
+ pcibus[busind].pb_bus, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func);
+#endif
+ PCII_WREG8_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port, value);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
+}
+
+static void
+pcii_wreg16(int busind, int devind, int port, u16_t value)
+{
+ int s;
+#if 0
+ printf("pcii_wreg16(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
+ busind, devind, port, value,
+ pcibus[busind].pb_bus, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func);
+#endif
+ PCII_WREG16_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port, value);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
+}
+
+static void
+pcii_wreg32(int busind, int devind, int port, u32_t value)
+{
+ int s;
+#if 0
+ printf("pcii_wreg32(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
+ busind, devind, port, value,
+ pcibus[busind].pb_busnr, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func);
+#endif
+ PCII_WREG32_(pcibus[busind].pb_busnr,
+ pcidev[devind].pd_dev, pcidev[devind].pd_func,
+ port, value);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n",s);
}
/*===========================================================================*
- * pci_reserve_a *
+ * ntostr *
*===========================================================================*/
-int pci_reserve_a(devind, proc, aclp)
-int devind;
-endpoint_t proc;
-struct rs_pci *aclp;
+static void
+ntostr(unsigned int n, char **str, const char *end)
{
- int i, r;
- int ilr;
- struct io_range ior;
- struct minix_mem_range mr;
+ char tmpstr[20];
+ int i;
- if (devind < 0 || devind >= nr_pcidev)
+ if (n == 0)
{
- printf("pci_reserve_a: bad devind: %d\n", devind);
- return EINVAL;
+ tmpstr[0]= '0';
+ i= 1;
}
- if (!visible(aclp, devind))
+ else
{
- printf("pci_reserve_a: %u is not allowed to reserve %d\n",
- proc, devind);
- return EPERM;
+ for (i= 0; n; i++)
+ {
+ tmpstr[i]= '0' + (n%10);
+ n /= 10;
+ }
}
-
- if(pcidev[devind].pd_inuse && pcidev[devind].pd_proc != proc)
- return EBUSY;
- pcidev[devind].pd_inuse= 1;
- pcidev[devind].pd_proc= proc;
-
- for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
- {
- if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
- {
- printf("pci_reserve_a: BAR %d is incomplete\n", i);
- continue;
- }
- if (pcidev[devind].pd_bar[i].pb_flags & PBF_IO)
- {
- ior.ior_base= pcidev[devind].pd_bar[i].pb_base;
- ior.ior_limit= ior.ior_base +
- pcidev[devind].pd_bar[i].pb_size-1;
-
- if(debug) {
- printf(
- "pci_reserve_a: for proc %d, adding I/O range [0x%x..0x%x]\n",
- proc, ior.ior_base, ior.ior_limit);
- }
- r= sys_privctl(proc, SYS_PRIV_ADD_IO, &ior);
- if (r != OK)
- {
- printf("sys_privctl failed for proc %d: %d\n",
- proc, r);
- }
- }
- else
- {
- mr.mr_base= pcidev[devind].pd_bar[i].pb_base;
- mr.mr_limit= mr.mr_base +
- pcidev[devind].pd_bar[i].pb_size-1;
-
- r= sys_privctl(proc, SYS_PRIV_ADD_MEM, &mr);
- if (r != OK)
- {
- printf("sys_privctl failed for proc %d: %d\n",
- proc, r);
- }
- }
- }
- ilr= pcidev[devind].pd_ilr;
- if (ilr != PCI_ILR_UNKNOWN)
+ for (; i>0; i--)
{
- if(debug) printf("pci_reserve_a: adding IRQ %d\n", ilr);
- r= sys_privctl(proc, SYS_PRIV_ADD_IRQ, &ilr);
- if (r != OK)
+ if (*str == end)
{
- printf("sys_privctl failed for proc %d: %d\n",
- proc, r);
+ break;
}
+ **str= tmpstr[i-1];
+ (*str)++;
}
-
- return OK;
+ if (*str == end)
+ (*str)[-1]= '\0';
+ else
+ **str= '\0';
}
/*===========================================================================*
- * pci_release *
+ * get_busind *
*===========================================================================*/
-void pci_release(proc)
-endpoint_t proc;
+static int
+get_busind(int busnr)
{
int i;
- for (i= 0; i<nr_pcidev; i++)
+ for (i= 0; i<nr_pcibus; i++)
{
- if (!pcidev[i].pd_inuse)
- continue;
- if (pcidev[i].pd_proc != proc)
- continue;
- pcidev[i].pd_inuse= 0;
+ if (pcibus[i].pb_busnr == busnr)
+ return i;
}
+ panic("get_busind: can't find bus: %d", busnr);
}
/*===========================================================================*
- * pci_ids_s *
- *===========================================================================*/
-int pci_ids_s(int devind, u16_t *vidp, u16_t *didp)
-{
- if (devind < 0 || devind >= nr_pcidev)
- return EINVAL;
-
- *vidp= pcidev[devind].pd_vid;
- *didp= pcidev[devind].pd_did;
- return OK;
-}
-
-/*===========================================================================*
- * pci_rescan_bus *
+ * Unprotected helper functions *
*===========================================================================*/
-void pci_rescan_bus(u8_t busnr)
+static u8_t
+__pci_attr_r8(int devind, int port)
{
- int busind;
+ int busnr, busind;
+ busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- probe_bus(busind);
-
- /* Allocate bus numbers for uninitialized bridges */
- complete_bridges();
-
- /* Allocate I/O and memory resources for uninitialized devices */
- complete_bars();
-}
-
-/*===========================================================================*
- * pci_slot_name_s *
- *===========================================================================*/
-int pci_slot_name_s(devind, cpp)
-int devind;
-char **cpp;
-{
- static char label[]= "ddd.ddd.ddd";
- char *end;
- char *p;
-
- if (devind < 0 || devind >= nr_pcidev)
- return EINVAL;
-
- p= label;
- end= label+sizeof(label);
-
- ntostr(pcidev[devind].pd_busnr, &p, end);
- *p++= '.';
-
- ntostr(pcidev[devind].pd_dev, &p, end);
- *p++= '.';
-
- ntostr(pcidev[devind].pd_func, &p, end);
-
- *cpp= label;
- return OK;
-}
-
-/*===========================================================================*
- * pci_dev_name *
- *===========================================================================*/
-char *pci_dev_name(u16_t vid, u16_t did)
-{
- int i;
-
- for (i= 0; pci_device_table[i].name; i++)
- {
- if (pci_device_table[i].vid == vid &&
- pci_device_table[i].did == did)
- {
- return pci_device_table[i].name;
- }
- }
- return NULL;
-}
-
-/*===========================================================================*
- * pci_get_bar_s *
- *===========================================================================*/
-int pci_get_bar_s(int devind, int port, u32_t *base, u32_t *size,
- int *ioflag)
-{
- int i, reg;
-
- if (devind < 0 || devind >= nr_pcidev)
- return EINVAL;
-
- for (i= 0; i < pcidev[devind].pd_bar_nr; i++)
- {
- reg= PCI_BAR+4*pcidev[devind].pd_bar[i].pb_nr;
-
- if (reg == port)
- {
- if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
- return EINVAL;
-
- *base= pcidev[devind].pd_bar[i].pb_base;
- *size= pcidev[devind].pd_bar[i].pb_size;
- *ioflag=
- !!(pcidev[devind].pd_bar[i].pb_flags & PBF_IO);
- return OK;
- }
- }
- return EINVAL;
-}
-
-/*===========================================================================*
- * pci_attr_r8_s *
- *===========================================================================*/
-int pci_attr_r8_s(int devind, int port, u8_t *vp)
-{
- if (devind < 0 || devind >= nr_pcidev)
- return EINVAL;
- if (port < 0 || port > 255)
- return EINVAL;
-
- *vp= pci_attr_r8_u(devind, port);
- return OK;
+ return pcibus[busind].pb_rreg8(busind, devind, port);
}
-/*===========================================================================*
- * pci_attr_r8_u *
- *===========================================================================*/
-static u8_t pci_attr_r8_u(devind, port)
-int devind;
-int port;
+static u16_t
+__pci_attr_r16(int devind, int port)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- return pcibus[busind].pb_rreg8(busind, devind, port);
+ return pcibus[busind].pb_rreg16(busind, devind, port);
}
-/*===========================================================================*
- * pci_attr_r16 *
- *===========================================================================*/
-u16_t pci_attr_r16(devind, port)
-int devind;
-int port;
+static u32_t
+__pci_attr_r32(int devind, int port)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- return pcibus[busind].pb_rreg16(busind, devind, port);
+ return pcibus[busind].pb_rreg32(busind, devind, port);
}
-/*===========================================================================*
- * pci_attr_r32_s *
- *===========================================================================*/
-int pci_attr_r32_s(int devind, int port, u32_t *vp)
+static void
+__pci_attr_w8(int devind, int port, u8_t value)
{
- if (devind < 0 || devind >= nr_pcidev)
- return EINVAL;
- if (port < 0 || port > 256-4)
- return EINVAL;
+ int busnr, busind;
- *vp= pci_attr_r32_u(devind, port);
- return OK;
+ busnr= pcidev[devind].pd_busnr;
+ busind= get_busind(busnr);
+ pcibus[busind].pb_wreg8(busind, devind, port, value);
}
-/*===========================================================================*
- * pci_attr_r32_u *
- *===========================================================================*/
-static u32_t pci_attr_r32_u(devind, port)
-int devind;
-int port;
+static void
+__pci_attr_w16(int devind, int port, u16_t value)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- return pcibus[busind].pb_rreg32(busind, devind, port);
+ pcibus[busind].pb_wreg16(busind, devind, port, value);
}
-/*===========================================================================*
- * pci_attr_w8 *
- *===========================================================================*/
-void pci_attr_w8(int devind, int port, u8_t value)
+static void
+__pci_attr_w32(int devind, int port, u32_t value)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- pcibus[busind].pb_wreg8(busind, devind, port, value);
+ pcibus[busind].pb_wreg32(busind, devind, port, value);
}
/*===========================================================================*
- * pci_attr_w16 *
+ * helpers *
*===========================================================================*/
-void pci_attr_w16(int devind, int port, u16_t value)
+static u16_t
+pci_attr_rsts(int devind)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- pcibus[busind].pb_wreg16(busind, devind, port, value);
+ return pcibus[busind].pb_rsts(busind);
}
-/*===========================================================================*
- * pci_attr_w32 *
- *===========================================================================*/
-void pci_attr_w32(int devind, int port, u32_t value)
+static void
+pci_attr_wsts(int devind, u16_t value)
{
int busnr, busind;
busnr= pcidev[devind].pd_busnr;
busind= get_busind(busnr);
- pcibus[busind].pb_wreg32(busind, devind, port, value);
+ pcibus[busind].pb_wsts(busind, value);
}
-/*===========================================================================*
- * pci_intel_init *
- *===========================================================================*/
-static void pci_intel_init()
+static u16_t
+pcii_rsts(int busind)
{
- /* Try to detect a know PCI controller. Read the Vendor ID and
- * the Device ID for function 0 of device 0.
- * Two times the value 0xffff suggests a system without a (compatible)
- * PCI controller.
- */
- u32_t bus, dev, func;
- u16_t vid, did;
- int s, i, r, busind, busnr;
- char *dstr;
+ u16_t v;
+ int s;
- bus= 0;
- dev= 0;
- func= 0;
+ v= PCII_RREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
+ return v;
+}
- vid= PCII_RREG16_(bus, dev, func, PCI_VID);
- did= PCII_RREG16_(bus, dev, func, PCI_DID);
+static void
+pcii_wsts(int busind, u16_t value)
+{
+ int s;
+ PCII_WREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR, value);
if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
printf("PCI: warning, sys_outl failed: %d\n", s);
+}
-#if 0
- if (vid == 0xffff && did == 0xffff)
- return; /* Nothing here */
+static int
+is_duplicate(u8_t busnr, u8_t dev, u8_t func)
+{
+ int i;
- for (i= 0; pci_intel_ctrl[i].vid; i++)
+ for (i= 0; i<nr_pcidev; i++)
{
- if (pci_intel_ctrl[i].vid == vid &&
- pci_intel_ctrl[i].did == did)
+ if (pcidev[i].pd_busnr == busnr &&
+ pcidev[i].pd_dev == dev &&
+ pcidev[i].pd_func == func)
{
- break;
+ return 1;
}
}
+ return 0;
+}
- if (!pci_intel_ctrl[i].vid)
- {
- printf("pci_intel_init (warning): unknown PCI-controller:\n"
- "\tvendor %04X (%s), device %04X\n",
- vid, pci_vid_name(vid), did);
- }
-#endif
+static int
+get_freebus(void)
+{
+ int i, freebus;
- if (nr_pcibus >= NR_PCIBUS)
- panic("too many PCI busses: %d", nr_pcibus);
- busind= nr_pcibus;
- nr_pcibus++;
- pcibus[busind].pb_type= PBT_INTEL_HOST;
- pcibus[busind].pb_needinit= 0;
- pcibus[busind].pb_isabridge_dev= -1;
- pcibus[busind].pb_isabridge_type= 0;
- pcibus[busind].pb_devind= -1;
- pcibus[busind].pb_busnr= 0;
- pcibus[busind].pb_rreg8= pcii_rreg8;
- pcibus[busind].pb_rreg16= pcii_rreg16;
- pcibus[busind].pb_rreg32= pcii_rreg32;
- pcibus[busind].pb_wreg8= pcii_wreg8;
- pcibus[busind].pb_wreg16= pcii_wreg16;
- pcibus[busind].pb_wreg32= pcii_wreg32;
- pcibus[busind].pb_rsts= pcii_rsts;
- pcibus[busind].pb_wsts= pcii_wsts;
-
- dstr= pci_dev_name(vid, did);
- if (!dstr)
- dstr= "unknown device";
- if (debug)
+ freebus= 1;
+ for (i= 0; i<nr_pcibus; i++)
{
- printf("pci_intel_init: %s (%04X:%04X)\n",
- dstr, vid, did);
+ if (pcibus[i].pb_needinit)
+ continue;
+ if (pcibus[i].pb_type == PBT_INTEL_HOST)
+ continue;
+ if (pcibus[i].pb_busnr <= freebus)
+ freebus= pcibus[i].pb_busnr+1;
+ printf("get_freebus: should check suboridinate bus number\n");
}
+ return freebus;
+}
- probe_bus(busind);
+static const char *
+pci_vid_name(u16_t vid)
+{
+ int i;
- r= do_isabridge(busind);
- if (r != OK)
+ for (i= 0; pci_vendor_table[i].name; i++)
{
- busnr= pcibus[busind].pb_busnr;
-
- /* Disable all devices for this bus */
- for (i= 0; i<nr_pcidev; i++)
- {
- if (pcidev[i].pd_busnr != busnr)
- continue;
- pcidev[i].pd_inuse= 1;
- }
- return;
+ if (pci_vendor_table[i].vid == vid)
+ return pci_vendor_table[i].name;
}
+ return "unknown";
+}
- /* Look for PCI bridges */
- do_pcibridge(busind);
- /* Allocate bus numbers for uninitialized bridges */
- complete_bridges();
+static const char *
+pci_baseclass_name(u8_t baseclass)
+{
+ int i;
- /* Allocate I/O and memory resources for uninitialized devices */
- complete_bars();
+ for (i= 0; pci_baseclass_table[i].name; i++)
+ {
+ if (pci_baseclass_table[i].baseclass == baseclass)
+ return pci_baseclass_table[i].name;
+ }
+ return NULL;
}
-/*===========================================================================*
- * probe_bus *
- *===========================================================================*/
-static void probe_bus(int busind)
+static const char *
+pci_subclass_name(u8_t baseclass, u8_t subclass, u8_t infclass)
{
- u32_t dev, func, t3;
- u16_t vid, did, sts, sub_vid, sub_did;
- u8_t headt;
- u8_t baseclass, subclass, infclass;
- int devind, busnr;
- char *s, *dstr;
-
- if (debug)
- printf("probe_bus(%d)\n", busind);
- if (nr_pcidev >= NR_PCIDEV)
- panic("too many PCI devices: %d", nr_pcidev);
- devind= nr_pcidev;
+ int i;
- busnr= pcibus[busind].pb_busnr;
- for (dev= 0; dev<32; dev++)
+ for (i= 0; pci_subclass_table[i].name; i++)
{
-
- for (func= 0; func < 8; func++)
+ if (pci_subclass_table[i].baseclass != baseclass)
+ continue;
+ if (pci_subclass_table[i].subclass != subclass)
+ continue;
+ if (pci_subclass_table[i].infclass != infclass &&
+ pci_subclass_table[i].infclass != (u16_t)-1)
{
- pcidev[devind].pd_busnr= busnr;
- pcidev[devind].pd_dev= dev;
- pcidev[devind].pd_func= func;
+ continue;
+ }
+ return pci_subclass_table[i].name;
+ }
+ return NULL;
+}
- pci_attr_wsts(devind,
- PSR_SSE|PSR_RMAS|PSR_RTAS);
- vid= pci_attr_r16(devind, PCI_VID);
- did= pci_attr_r16(devind, PCI_DID);
- headt= pci_attr_r8_u(devind, PCI_HEADT);
- sts= pci_attr_rsts(devind);
+static void
+print_hyper_cap(int devind, u8_t capptr)
+{
+ u32_t v;
+ u16_t cmd;
+ int type0, type1;
+ printf("\n");
+ v= __pci_attr_r32(devind, capptr);
+ printf("print_hyper_cap: @0x%x, off 0 (cap):", capptr);
+ cmd= (v >> 16) & 0xffff;
#if 0
- printf("vid 0x%x, did 0x%x, headt 0x%x, sts 0x%x\n",
- vid, did, headt, sts);
+ if (v & 0x10000)
+ {
+ printf(" WarmReset");
+ v &= ~0x10000;
+ }
+ if (v & 0x20000)
+ {
+ printf(" DblEnded");
+ v &= ~0x20000;
+ }
+ printf(" DevNum %d", (v & 0x7C0000) >> 18);
+ v &= ~0x7C0000;
#endif
+ type0= (cmd & 0xE000) >> 13;
+ type1= (cmd & 0xF800) >> 11;
+ if (type0 == 0 || type0 == 1)
+ {
+ printf("Capability Type: %s\n",
+ type0 == 0 ? "Slave or Primary Interface" :
+ "Host or Secondary Interface");
+ cmd &= ~0xE000;
+ }
+ else
+ {
+ printf(" Capability Type 0x%x", type1);
+ cmd &= ~0xF800;
+ }
+ if (cmd)
+ printf(" undecoded 0x%x\n", cmd);
- if (vid == NO_VID && did == NO_VID)
- {
- if (func == 0)
- break; /* Nothing here */
-
- /* Scan all functions of a multifunction
- * device.
- */
- continue;
- }
-
- if (sts & (PSR_SSE|PSR_RMAS|PSR_RTAS))
- {
- static int warned = 0;
-
- if(!warned) {
- printf(
- "PCI: ignoring bad value 0x%x in sts for QEMU\n",
- sts & (PSR_SSE|PSR_RMAS|PSR_RTAS));
- warned = 1;
- }
- }
-
- sub_vid= pci_attr_r16(devind, PCI_SUBVID);
- sub_did= pci_attr_r16(devind, PCI_SUBDID);
+#if 0
+ printf("print_hyper_cap: off 4 (ctl): 0x%x\n",
+ __pci_attr_r32(devind, capptr+4));
+ printf("print_hyper_cap: off 8 (freq/rev): 0x%x\n",
+ __pci_attr_r32(devind, capptr+8));
+ printf("print_hyper_cap: off 12 (cap): 0x%x\n",
+ __pci_attr_r32(devind, capptr+12));
+ printf("print_hyper_cap: off 16 (buf count): 0x%x\n",
+ __pci_attr_r32(devind, capptr+16));
+ v= __pci_attr_r32(devind, capptr+20);
+ printf("print_hyper_cap: @0x%x, off 20 (bus nr): ",
+ capptr+20);
+ printf("prim %d", v & 0xff);
+ printf(", sec %d", (v >> 8) & 0xff);
+ printf(", sub %d", (v >> 16) & 0xff);
+ if (v >> 24)
+ printf(", reserved %d", (v >> 24) & 0xff);
+ printf("\n");
+ printf("print_hyper_cap: off 24 (type): 0x%x\n",
+ __pci_attr_r32(devind, capptr+24));
+#endif
+}
- dstr= pci_dev_name(vid, did);
- if (debug)
- {
- if (dstr)
- {
- printf("%d.%lu.%lu: %s (%04X:%04X)\n",
- busnr, (unsigned long)dev,
- (unsigned long)func, dstr,
- vid, did);
- }
- else
- {
- printf(
- "%d.%lu.%lu: Unknown device, vendor %04X (%s), device %04X\n",
- busnr, (unsigned long)dev,
- (unsigned long)func, vid,
- pci_vid_name(vid), did);
- }
- printf("Device index: %d\n", devind);
- printf("Subsystem: Vid 0x%x, did 0x%x\n",
- sub_vid, sub_did);
- }
+static void
+print_capabilities(int devind)
+{
+ u8_t status, capptr, type, next, subtype;
+ const char *str;
- baseclass= pci_attr_r8_u(devind, PCI_BCR);
- subclass= pci_attr_r8_u(devind, PCI_SCR);
- infclass= pci_attr_r8_u(devind, PCI_PIFR);
- s= pci_subclass_name(baseclass, subclass, infclass);
- if (!s)
- s= pci_baseclass_name(baseclass);
- {
- if (!s)
- s= "(unknown class)";
- }
- if (debug)
- {
- printf("\tclass %s (%X/%X/%X)\n", s,
- baseclass, subclass, infclass);
- }
+ /* Check capabilities bit in the device status register */
+ status= __pci_attr_r16(devind, PCI_SR);
+ if (!(status & PSR_CAPPTR))
+ return;
- if (is_duplicate(busnr, dev, func))
- {
- printf("\tduplicate!\n");
- if (func == 0 && !(headt & PHT_MULTIFUNC))
- break;
- continue;
- }
+ capptr= (__pci_attr_r8(devind, PCI_CAPPTR) & PCI_CP_MASK);
+ while (capptr != 0)
+ {
+ type = __pci_attr_r8(devind, capptr+CAP_TYPE);
+ next= (__pci_attr_r8(devind, capptr+CAP_NEXT) & PCI_CP_MASK);
+ switch(type)
+ {
+ case 1: str= "PCI Power Management"; break;
+ case 2: str= "AGP"; break;
+ case 3: str= "Vital Product Data"; break;
+ case 4: str= "Slot Identification"; break;
+ case 5: str= "Message Signaled Interrupts"; break;
+ case 6: str= "CompactPCI Hot Swap"; break;
+ case 8: str= "AMD HyperTransport"; break;
+ case 0xf: str= "Secure Device"; break;
+ default: str= "(unknown type)"; break;
+ }
- devind= nr_pcidev;
- nr_pcidev++;
- pcidev[devind].pd_baseclass= baseclass;
- pcidev[devind].pd_subclass= subclass;
- pcidev[devind].pd_infclass= infclass;
- pcidev[devind].pd_vid= vid;
- pcidev[devind].pd_did= did;
- pcidev[devind].pd_sub_vid= sub_vid;
- pcidev[devind].pd_sub_did= sub_did;
- pcidev[devind].pd_inuse= 0;
- pcidev[devind].pd_bar_nr= 0;
- record_irq(devind);
- switch(headt & PHT_MASK)
+ printf(" @0x%x (0x%08x): capability type 0x%x: %s",
+ capptr, __pci_attr_r32(devind, capptr), type, str);
+ if (type == 0x08)
+ print_hyper_cap(devind, capptr);
+ else if (type == 0x0f)
+ {
+ subtype= (__pci_attr_r8(devind, capptr+2) & 0x07);
+ switch(subtype)
{
- case PHT_NORMAL:
- record_bars_normal(devind);
- break;
- case PHT_BRIDGE:
- record_bars_bridge(devind);
- break;
- case PHT_CARDBUS:
- record_bars_cardbus(devind);
- break;
- default:
- printf("\t%d.%d.%d: unknown header type %d\n",
- busind, dev, func,
- headt & PHT_MASK);
- break;
+ case 0: str= "Device Exclusion Vector"; break;
+ case 3: str= "IOMMU"; break;
+ default: str= "(unknown type)"; break;
}
- if (debug)
- print_capabilities(devind);
-
- t3= ((baseclass << 16) | (subclass << 8) | infclass);
-#if 0
- if (t3 == PCI_T3_VGA || t3 == PCI_T3_VGA_OLD)
- report_vga(devind);
-#endif
-
- if (nr_pcidev >= NR_PCIDEV)
- panic("too many PCI devices: %d", nr_pcidev);
- devind= nr_pcidev;
-
- if (func == 0 && !(headt & PHT_MULTIFUNC))
- break;
+ printf(", sub type 0%o: %s", subtype, str);
}
+ printf("\n");
+ capptr= next;
}
}
/*===========================================================================*
- * is_duplicate *
+ * ISA Bridge Helpers *
*===========================================================================*/
-static int is_duplicate(u8_t busnr, u8_t dev, u8_t func)
+static void
+update_bridge4dev_io(int devind, u32_t io_base, u32_t io_size)
{
- int i;
+ int busnr, busind, type, br_devind;
+ u16_t v16;
- for (i= 0; i<nr_pcidev; i++)
+ busnr= pcidev[devind].pd_busnr;
+ busind= get_busind(busnr);
+ type= pcibus[busind].pb_type;
+ if (type == PBT_INTEL_HOST)
+ return; /* Nothing to do for host controller */
+ if (type == PBT_PCIBRIDGE)
{
- if (pcidev[i].pd_busnr == busnr &&
- pcidev[i].pd_dev == dev &&
- pcidev[i].pd_func == func)
- {
- return 1;
- }
+ printf(
+ "update_bridge4dev_io: not implemented for PCI bridges\n");
+ return;
}
- return 0;
-}
-
-static int acpi_get_irq(unsigned bus, unsigned dev, unsigned pin)
-{
- int err;
- message m;
-
- ((struct acpi_get_irq_req *)&m)->hdr.request = ACPI_REQ_GET_IRQ;
- ((struct acpi_get_irq_req *)&m)->bus = bus;
- ((struct acpi_get_irq_req *)&m)->dev = dev;
- ((struct acpi_get_irq_req *)&m)->pin = pin;
-
- if ((err = ipc_sendrec(acpi_ep, &m)) != OK)
- panic("PCI: error %d while receiveing from ACPI\n", err);
-
- return ((struct acpi_get_irq_resp *)&m)->irq;
-}
-
-static int derive_irq(struct pcidev * dev, int pin)
-{
- struct pcidev * parent_bridge;
- int slot;
-
- parent_bridge = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
+ if (type != PBT_CARDBUS)
+ panic("update_bridge4dev_io: strange bus type: %d", type);
- /*
- * We don't support PCI-Express, no ARI, decode the slot of the device
- * and mangle the pin as the device is behind a bridge
- */
- slot = ((dev->pd_func) >> 3) & 0x1f;
+ if (debug)
+ {
+ printf("update_bridge4dev_io: adding 0x%x at 0x%x\n",
+ io_size, io_base);
+ }
+ br_devind= pcibus[busind].pb_devind;
+ __pci_attr_w32(br_devind, CBB_IOLIMIT_0, io_base+io_size-1);
+ __pci_attr_w32(br_devind, CBB_IOBASE_0, io_base);
- return acpi_get_irq(parent_bridge->pd_busnr,
- parent_bridge->pd_dev, (pin + slot) % 4);
+ /* Enable I/O access. Enable busmaster access as well. */
+ v16= __pci_attr_r16(devind, PCI_CR);
+ __pci_attr_w16(devind, PCI_CR, v16 | PCI_CR_IO_EN | PCI_CR_MAST_EN);
}
-/*===========================================================================*
- * record_irq *
- *===========================================================================*/
-static void record_irq(devind)
-int devind;
+static int
+do_piix(int devind)
{
- int ilr, ipr, busnr, busind, cb_devind;
-
- ilr= pci_attr_r8_u(devind, PCI_ILR);
- ipr= pci_attr_r8_u(devind, PCI_IPR);
-
- if (ipr && machine.apic_enabled) {
- int irq;
-
- irq = acpi_get_irq(pcidev[devind].pd_busnr,
- pcidev[devind].pd_dev, ipr - 1);
-
- if (irq < 0)
- irq = derive_irq(&pcidev[devind], ipr - 1);
-
- if (irq >= 0) {
- ilr = irq;
- pci_attr_w8(devind, PCI_ILR, ilr);
- if (debug)
- printf("PCI: ACPI IRQ %d for "
- "device %d.%d.%d INT%c\n",
- irq,
- pcidev[devind].pd_busnr,
- pcidev[devind].pd_dev,
- pcidev[devind].pd_func,
- 'A' + ipr-1);
- }
- else if (debug) {
- printf("PCI: no ACPI IRQ routing for "
- "device %d.%d.%d INT%c\n",
- pcidev[devind].pd_busnr,
- pcidev[devind].pd_dev,
- pcidev[devind].pd_func,
- 'A' + ipr-1);
- }
- }
+ int i, s, irqrc, irq;
+ u32_t elcr1, elcr2, elcr;
- if (ilr == 0)
+#if DEBUG
+ printf("in piix\n");
+#endif
+ if (OK != (s=sys_inb(PIIX_ELCR1, &elcr1)))
+ printf("Warning, sys_inb failed: %d\n", s);
+ if (OK != (s=sys_inb(PIIX_ELCR2, &elcr2)))
+ printf("Warning, sys_inb failed: %d\n", s);
+ elcr= elcr1 | (elcr2 << 8);
+ for (i= 0; i<4; i++)
{
- static int first= 1;
- if (ipr && first && debug)
+ irqrc= __pci_attr_r8(devind, PIIX_PIRQRCA+i);
+ if (irqrc & PIIX_IRQ_DI)
{
- first= 0;
- printf("PCI: strange, BIOS assigned IRQ0\n");
+ if (debug)
+ printf("INT%c: disabled\n", 'A'+i);
}
- ilr= PCI_ILR_UNKNOWN;
- }
- pcidev[devind].pd_ilr= ilr;
- if (ilr == PCI_ILR_UNKNOWN && !ipr)
- {
- }
- else if (ilr != PCI_ILR_UNKNOWN && ipr)
- {
- if (debug)
- printf("\tIRQ %d for INT%c\n", ilr, 'A' + ipr-1);
- }
- else if (ilr != PCI_ILR_UNKNOWN)
- {
- printf(
- "PCI: IRQ %d is assigned, but device %d.%d.%d does not need it\n",
- ilr, pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
- pcidev[devind].pd_func);
- }
- else
- {
- /* Check for cardbus devices */
- busnr= pcidev[devind].pd_busnr;
- busind= get_busind(busnr);
- if (pcibus[busind].pb_type == PBT_CARDBUS)
+ else
{
- cb_devind= pcibus[busind].pb_devind;
- ilr= pcidev[cb_devind].pd_ilr;
- if (ilr != PCI_ILR_UNKNOWN)
+ irq= irqrc & PIIX_IRQ_MASK;
+ if (debug)
+ printf("INT%c: %d\n", 'A'+i, irq);
+ if (!(elcr & (1 << irq)))
{
if (debug)
{
printf(
- "assigning IRQ %d to Cardbus device\n",
- ilr);
+ "(warning) IRQ %d is not level triggered\n",
+ irq);
}
- pci_attr_w8(devind, PCI_ILR, ilr);
- pcidev[devind].pd_ilr= ilr;
- return;
}
- }
- if(debug) {
- printf(
- "PCI: device %d.%d.%d uses INT%c but is not assigned any IRQ\n",
- pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
- pcidev[devind].pd_func, 'A' + ipr-1);
+ irq_mode_pci(irq);
}
}
+ return 0;
}
-/*===========================================================================*
- * record_bars_normal *
- *===========================================================================*/
-static void record_bars_normal(devind)
-int devind;
+static int
+do_amd_isabr(int devind)
{
- int i, j, clear_01, clear_23, pb_nr;
+ int i, busnr, dev, func, xdevind, irq, edge;
+ u8_t levmask;
+ u16_t pciirq;
- /* The BAR area of normal devices is six DWORDs in size. */
- record_bars(devind, PCI_BAR_6);
+ /* Find required function */
+ func= AMD_ISABR_FUNC;
+ busnr= pcidev[devind].pd_busnr;
+ dev= pcidev[devind].pd_dev;
- /* Special case code for IDE controllers in compatibility mode */
- if (pcidev[devind].pd_baseclass == PCI_BCR_MASS_STORAGE &&
- pcidev[devind].pd_subclass == PCI_MS_IDE)
+ /* Fake a device with the required function */
+ if (nr_pcidev >= NR_PCIDEV)
+ panic("too many PCI devices: %d", nr_pcidev);
+ xdevind= nr_pcidev;
+ pcidev[xdevind].pd_busnr= busnr;
+ pcidev[xdevind].pd_dev= dev;
+ pcidev[xdevind].pd_func= func;
+ pcidev[xdevind].pd_inuse= 1;
+ nr_pcidev++;
+
+ levmask= __pci_attr_r8(xdevind, AMD_ISABR_PCIIRQ_LEV);
+ pciirq= __pci_attr_r16(xdevind, AMD_ISABR_PCIIRQ_ROUTE);
+ for (i= 0; i<4; i++)
{
- /* IDE device */
- clear_01= 0;
- clear_23= 0;
- if (!(pcidev[devind].pd_infclass & PCI_IDE_PRI_NATIVE))
+ edge= (levmask >> i) & 1;
+ irq= (pciirq >> (4*i)) & 0xf;
+ if (!irq)
{
if (debug)
- {
- printf(
- "primary channel is not in native mode, clearing BARs 0 and 1\n");
- }
- clear_01= 1;
+ printf("INT%c: disabled\n", 'A'+i);
}
- if (!(pcidev[devind].pd_infclass & PCI_IDE_SEC_NATIVE))
+ else
{
if (debug)
+ printf("INT%c: %d\n", 'A'+i, irq);
+ if (edge && debug)
{
printf(
- "secondary channel is not in native mode, clearing BARs 2 and 3\n");
+ "(warning) IRQ %d is not level triggered\n",
+ irq);
}
- clear_23= 1;
+ irq_mode_pci(irq);
}
+ }
+ nr_pcidev--;
+ return 0;
+}
- j= 0;
- for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
+static int
+do_sis_isabr(int devind)
+{
+ int i, irq;
+
+ irq= 0; /* lint */
+ for (i= 0; i<4; i++)
+ {
+ irq= __pci_attr_r8(devind, SIS_ISABR_IRQ_A+i);
+ if (irq & SIS_IRQ_DISABLED)
{
- pb_nr= pcidev[devind].pd_bar[i].pb_nr;
- if ((pb_nr == 0 || pb_nr == 1) && clear_01)
- {
- if (debug) printf("skipping bar %d\n", pb_nr);
- continue; /* Skip */
- }
- if ((pb_nr == 2 || pb_nr == 3) && clear_23)
- {
- if (debug) printf("skipping bar %d\n", pb_nr);
- continue; /* Skip */
- }
- if (i == j)
+ if (debug)
+ printf("INT%c: disabled\n", 'A'+i);
+ }
+ else
+ {
+ irq &= SIS_IRQ_MASK;
+ if (debug)
+ printf("INT%c: %d\n", 'A'+i, irq);
+ irq_mode_pci(irq);
+ }
+ }
+ return 0;
+}
+
+static int
+do_via_isabr(int devind)
+{
+ int i, irq, edge;
+ u8_t levmask;
+
+ levmask= __pci_attr_r8(devind, VIA_ISABR_EL);
+ irq= 0; /* lint */
+ edge= 0; /* lint */
+ for (i= 0; i<4; i++)
+ {
+ switch(i)
+ {
+ case 0:
+ edge= (levmask & VIA_ISABR_EL_INTA);
+ irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R2) >> 4;
+ break;
+ case 1:
+ edge= (levmask & VIA_ISABR_EL_INTB);
+ irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R2);
+ break;
+ case 2:
+ edge= (levmask & VIA_ISABR_EL_INTC);
+ irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R3) >> 4;
+ break;
+ case 3:
+ edge= (levmask & VIA_ISABR_EL_INTD);
+ irq= __pci_attr_r8(devind, VIA_ISABR_IRQ_R1) >> 4;
+ break;
+ default:
+ panic("PCI: VIA ISA Bridge IRQ Detection Failed");
+ }
+ irq &= 0xf;
+ if (!irq)
+ {
+ if (debug)
+ printf("INT%c: disabled\n", 'A'+i);
+ }
+ else
+ {
+ if (debug)
+ printf("INT%c: %d\n", 'A'+i, irq);
+ if (edge && debug)
{
- j++;
- continue; /* No need to copy */
+ printf(
+ "(warning) IRQ %d is not level triggered\n",
+ irq);
}
- pcidev[devind].pd_bar[j]=
- pcidev[devind].pd_bar[i];
- j++;
+ irq_mode_pci(irq);
}
- pcidev[devind].pd_bar_nr= j;
}
+ return 0;
}
-/*===========================================================================*
- * record_bars_bridge *
- *===========================================================================*/
-static void record_bars_bridge(devind)
-int devind;
+static int
+do_isabridge(int busind)
{
- u32_t base, limit, size;
-
- /* The generic BAR area of PCI-to-PCI bridges is two DWORDs in size.
- * It may contain up to two 32-bit BARs, or one 64-bit BAR.
- */
- record_bars(devind, PCI_BAR_2);
+ int i, j, r, type, busnr, unknown_bridge, bridge_dev;
+ u16_t vid, did;
+ u32_t t3;
+ const char *dstr;
- base= ((pci_attr_r8_u(devind, PPB_IOBASE) & PPB_IOB_MASK) << 8) |
- (pci_attr_r16(devind, PPB_IOBASEU16) << 16);
- limit= 0xff |
- ((pci_attr_r8_u(devind, PPB_IOLIMIT) & PPB_IOL_MASK) << 8) |
- ((~PPB_IOL_MASK & 0xff) << 8) |
- (pci_attr_r16(devind, PPB_IOLIMITU16) << 16);
- size= limit-base + 1;
- if (debug)
+ unknown_bridge= -1;
+ bridge_dev= -1;
+ j= 0; /* lint */
+ vid= did= 0; /* lint */
+ busnr= pcibus[busind].pb_busnr;
+ for (i= 0; i< nr_pcidev; i++)
{
- printf("\tI/O window: base 0x%x, limit 0x%x, size %d\n",
- base, limit, size);
+ if (pcidev[i].pd_busnr != busnr)
+ continue;
+ t3= ((pcidev[i].pd_baseclass << 16) |
+ (pcidev[i].pd_subclass << 8) | pcidev[i].pd_infclass);
+ if (t3 == PCI_T3_ISA)
+ {
+ /* ISA bridge. Report if no supported bridge is
+ * found.
+ */
+ unknown_bridge= i;
+ }
+
+ vid= pcidev[i].pd_vid;
+ did= pcidev[i].pd_did;
+ for (j= 0; pci_isabridge[j].vid != 0; j++)
+ {
+ if (pci_isabridge[j].vid != vid)
+ continue;
+ if (pci_isabridge[j].did != did)
+ continue;
+ if (pci_isabridge[j].checkclass &&
+ unknown_bridge != i)
+ {
+ /* This part of multifunction device is
+ * not the bridge.
+ */
+ continue;
+ }
+ break;
+ }
+ if (pci_isabridge[j].vid)
+ {
+ bridge_dev= i;
+ break;
+ }
}
- base= ((pci_attr_r16(devind, PPB_MEMBASE) & PPB_MEMB_MASK) << 16);
- limit= 0xffff |
- ((pci_attr_r16(devind, PPB_MEMLIMIT) & PPB_MEML_MASK) << 16) |
- ((~PPB_MEML_MASK & 0xffff) << 16);
- size= limit-base + 1;
- if (debug)
+ if (bridge_dev != -1)
{
- printf("\tMemory window: base 0x%x, limit 0x%x, size 0x%x\n",
- base, limit, size);
+ dstr= _pci_dev_name(vid, did);
+ if (!dstr)
+ dstr= "unknown device";
+ if (debug)
+ {
+ printf("found ISA bridge (%04X:%04X) %s\n",
+ vid, did, dstr);
+ }
+ pcibus[busind].pb_isabridge_dev= bridge_dev;
+ type= pci_isabridge[j].type;
+ pcibus[busind].pb_isabridge_type= type;
+ switch(type)
+ {
+ case PCI_IB_PIIX:
+ r= do_piix(bridge_dev);
+ break;
+ case PCI_IB_VIA:
+ r= do_via_isabr(bridge_dev);
+ break;
+ case PCI_IB_AMD:
+ r= do_amd_isabr(bridge_dev);
+ break;
+ case PCI_IB_SIS:
+ r= do_sis_isabr(bridge_dev);
+ break;
+ default:
+ panic("unknown ISA bridge type: %d", type);
+ }
+ return r;
}
- /* Ignore the upper 32 bits */
- base= ((pci_attr_r16(devind, PPB_PFMEMBASE) & PPB_PFMEMB_MASK) << 16);
- limit= 0xffff |
- ((pci_attr_r16(devind, PPB_PFMEMLIMIT) &
- PPB_PFMEML_MASK) << 16) |
- ((~PPB_PFMEML_MASK & 0xffff) << 16);
- size= limit-base + 1;
+ if (unknown_bridge == -1)
+ {
+ if (debug)
+ {
+ printf("(warning) no ISA bridge found on bus %d\n",
+ busind);
+ }
+ return 0;
+ }
if (debug)
{
printf(
- "\tPrefetchable memory window: base 0x%x, limit 0x%x, size 0x%x\n",
- base, limit, size);
+ "(warning) unsupported ISA bridge %04X:%04X for bus %d\n",
+ pcidev[unknown_bridge].pd_vid,
+ pcidev[unknown_bridge].pd_did, busind);
}
+ return 0;
}
/*===========================================================================*
- * record_bars_cardbus *
+ * IRQ handling *
*===========================================================================*/
-static void record_bars_cardbus(devind)
-int devind;
+static int
+acpi_get_irq(unsigned bus, unsigned dev, unsigned pin)
{
- u32_t base, limit, size;
+ int err;
+ message m;
- /* The generic BAR area of CardBus devices is one DWORD in size. */
- record_bars(devind, PCI_BAR);
+ ((struct acpi_get_irq_req *)&m)->hdr.request = ACPI_REQ_GET_IRQ;
+ ((struct acpi_get_irq_req *)&m)->bus = bus;
+ ((struct acpi_get_irq_req *)&m)->dev = dev;
+ ((struct acpi_get_irq_req *)&m)->pin = pin;
- base= pci_attr_r32_u(devind, CBB_MEMBASE_0);
- limit= pci_attr_r32_u(devind, CBB_MEMLIMIT_0) |
- (~CBB_MEML_MASK & 0xffffffff);
- size= limit-base + 1;
- if (debug)
- {
- printf("\tMemory window 0: base 0x%x, limit 0x%x, size %d\n",
- base, limit, size);
+ if ((err = ipc_sendrec(acpi_ep, &m)) != OK)
+ panic("PCI: error %d while receiveing from ACPI\n", err);
+
+ return ((struct acpi_get_irq_resp *)&m)->irq;
+}
+
+static int
+derive_irq(struct pcidev * dev, int pin)
+{
+ struct pcidev * parent_bridge;
+ int slot;
+
+ parent_bridge = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
+
+ /*
+ * We don't support PCI-Express, no ARI, decode the slot of the device
+ * and mangle the pin as the device is behind a bridge
+ */
+ slot = ((dev->pd_func) >> 3) & 0x1f;
+
+ return acpi_get_irq(parent_bridge->pd_busnr,
+ parent_bridge->pd_dev, (pin + slot) % 4);
+}
+
+static void
+record_irq(int devind)
+{
+ int ilr, ipr, busnr, busind, cb_devind;
+
+ ilr= __pci_attr_r8(devind, PCI_ILR);
+ ipr= __pci_attr_r8(devind, PCI_IPR);
+
+ if (ipr && machine.apic_enabled) {
+ int irq;
+
+ irq = acpi_get_irq(pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev, ipr - 1);
+
+ if (irq < 0)
+ irq = derive_irq(&pcidev[devind], ipr - 1);
+
+ if (irq >= 0) {
+ ilr = irq;
+ __pci_attr_w8(devind, PCI_ILR, ilr);
+ if (debug)
+ printf("PCI: ACPI IRQ %d for "
+ "device %d.%d.%d INT%c\n",
+ irq,
+ pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev,
+ pcidev[devind].pd_func,
+ 'A' + ipr-1);
+ }
+ else if (debug) {
+ printf("PCI: no ACPI IRQ routing for "
+ "device %d.%d.%d INT%c\n",
+ pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev,
+ pcidev[devind].pd_func,
+ 'A' + ipr-1);
+ }
}
- base= pci_attr_r32_u(devind, CBB_MEMBASE_1);
- limit= pci_attr_r32_u(devind, CBB_MEMLIMIT_1) |
- (~CBB_MEML_MASK & 0xffffffff);
- size= limit-base + 1;
- if (debug)
+ if (ilr == 0)
{
- printf("\tMemory window 1: base 0x%x, limit 0x%x, size %d\n",
- base, limit, size);
+ static int first= 1;
+ if (ipr && first && debug)
+ {
+ first= 0;
+ printf("PCI: strange, BIOS assigned IRQ0\n");
+ }
+ ilr= PCI_ILR_UNKNOWN;
}
-
- base= pci_attr_r32_u(devind, CBB_IOBASE_0);
- limit= pci_attr_r32_u(devind, CBB_IOLIMIT_0) |
- (~CBB_IOL_MASK & 0xffffffff);
- size= limit-base + 1;
- if (debug)
+ pcidev[devind].pd_ilr= ilr;
+ if (ilr == PCI_ILR_UNKNOWN && !ipr)
{
- printf("\tI/O window 0: base 0x%x, limit 0x%x, size %d\n",
- base, limit, size);
}
-
- base= pci_attr_r32_u(devind, CBB_IOBASE_1);
- limit= pci_attr_r32_u(devind, CBB_IOLIMIT_1) |
- (~CBB_IOL_MASK & 0xffffffff);
- size= limit-base + 1;
- if (debug)
+ else if (ilr != PCI_ILR_UNKNOWN && ipr)
{
- printf("\tI/O window 1: base 0x%x, limit 0x%x, size %d\n",
- base, limit, size);
+ if (debug)
+ printf("\tIRQ %d for INT%c\n", ilr, 'A' + ipr-1);
}
-}
-
-/*===========================================================================*
- * record_bars *
- *===========================================================================*/
-static void record_bars(int devind, int last_reg)
-{
- int i, reg, width;
-
- for (i= 0, reg= PCI_BAR; reg <= last_reg; i += width, reg += 4 * width)
+ else if (ilr != PCI_ILR_UNKNOWN)
{
- width = record_bar(devind, i, reg == last_reg);
+ printf(
+ "PCI: IRQ %d is assigned, but device %d.%d.%d does not need it\n",
+ ilr, pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func);
+ }
+ else
+ {
+ /* Check for cardbus devices */
+ busnr= pcidev[devind].pd_busnr;
+ busind= get_busind(busnr);
+ if (pcibus[busind].pb_type == PBT_CARDBUS)
+ {
+ cb_devind= pcibus[busind].pb_devind;
+ ilr= pcidev[cb_devind].pd_ilr;
+ if (ilr != PCI_ILR_UNKNOWN)
+ {
+ if (debug)
+ {
+ printf(
+ "assigning IRQ %d to Cardbus device\n",
+ ilr);
+ }
+ __pci_attr_w8(devind, PCI_ILR, ilr);
+ pcidev[devind].pd_ilr= ilr;
+ return;
+ }
+ }
+ if(debug) {
+ printf(
+ "PCI: device %d.%d.%d uses INT%c but is not assigned any IRQ\n",
+ pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
+ pcidev[devind].pd_func, 'A' + ipr-1);
+ }
}
}
/*===========================================================================*
- * record_bar *
+ * BAR helpers *
*===========================================================================*/
-static int record_bar(devind, bar_nr, last)
-int devind;
-int bar_nr;
-int last;
+static int
+record_bar(int devind, int bar_nr, int last)
{
int reg, prefetch, type, dev_bar_nr, width;
u32_t bar, bar2;
reg= PCI_BAR+4*bar_nr;
- bar= pci_attr_r32_u(devind, reg);
+ bar= __pci_attr_r32(devind, reg);
if (bar & PCI_BAR_IO)
{
/* Disable I/O access before probing for BAR's size */
- cmd = pci_attr_r16(devind, PCI_CR);
- pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_IO_EN);
+ cmd = __pci_attr_r16(devind, PCI_CR);
+ __pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_IO_EN);
/* Probe BAR's size */
- pci_attr_w32(devind, reg, 0xffffffff);
- bar2= pci_attr_r32_u(devind, reg);
+ __pci_attr_w32(devind, reg, 0xffffffff);
+ bar2= __pci_attr_r32(devind, reg);
/* Restore original state */
- pci_attr_w32(devind, reg, bar);
- pci_attr_w16(devind, PCI_CR, cmd);
+ __pci_attr_w32(devind, reg, bar);
+ __pci_attr_w16(devind, PCI_CR, cmd);
bar &= PCI_BAR_IO_MASK; /* Clear non-address bits */
bar2 &= PCI_BAR_IO_MASK;
pcidev[devind].pd_bar[dev_bar_nr].pb_nr= bar_nr;
if (bar == 0)
{
- pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
+ pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
PBF_INCOMPLETE;
}
}
}
width++;
- bar2= pci_attr_r32_u(devind, reg+4);
+ bar2= __pci_attr_r32(devind, reg+4);
/* If the upper 32 bits of the BAR are not zero, the
* memory is inaccessible to us; ignore the BAR.
}
/* Disable mem access before probing for BAR's size */
- cmd = pci_attr_r16(devind, PCI_CR);
- pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_MEM_EN);
+ cmd = __pci_attr_r16(devind, PCI_CR);
+ __pci_attr_w16(devind, PCI_CR, cmd & ~PCI_CR_MEM_EN);
/* Probe BAR's size */
- pci_attr_w32(devind, reg, 0xffffffff);
- bar2= pci_attr_r32_u(devind, reg);
+ __pci_attr_w32(devind, reg, 0xffffffff);
+ bar2= __pci_attr_r32(devind, reg);
/* Restore original values */
- pci_attr_w32(devind, reg, bar);
- pci_attr_w16(devind, PCI_CR, cmd);
+ __pci_attr_w32(devind, reg, bar);
+ __pci_attr_w16(devind, PCI_CR, cmd);
if (bar2 == 0)
return width; /* Reg. is not implemented */
pcidev[devind].pd_bar[dev_bar_nr].pb_nr= bar_nr;
if (bar == 0)
{
- pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
+ pcidev[devind].pd_bar[dev_bar_nr].pb_flags |=
PBF_INCOMPLETE;
}
}
-
- return width;
+
+ return width;
+}
+
+static void
+record_bars(int devind, int last_reg)
+{
+ int i, reg, width;
+
+ for (i= 0, reg= PCI_BAR; reg <= last_reg; i += width, reg += 4 * width)
+ {
+ width = record_bar(devind, i, reg == last_reg);
+ }
+}
+
+static void
+record_bars_normal(int devind)
+{
+ int i, j, clear_01, clear_23, pb_nr;
+
+ /* The BAR area of normal devices is six DWORDs in size. */
+ record_bars(devind, PCI_BAR_6);
+
+ /* Special case code for IDE controllers in compatibility mode */
+ if (pcidev[devind].pd_baseclass == PCI_BCR_MASS_STORAGE &&
+ pcidev[devind].pd_subclass == PCI_MS_IDE)
+ {
+ /* IDE device */
+ clear_01= 0;
+ clear_23= 0;
+ if (!(pcidev[devind].pd_infclass & PCI_IDE_PRI_NATIVE))
+ {
+ if (debug)
+ {
+ printf(
+ "primary channel is not in native mode, clearing BARs 0 and 1\n");
+ }
+ clear_01= 1;
+ }
+ if (!(pcidev[devind].pd_infclass & PCI_IDE_SEC_NATIVE))
+ {
+ if (debug)
+ {
+ printf(
+ "secondary channel is not in native mode, clearing BARs 2 and 3\n");
+ }
+ clear_23= 1;
+ }
+
+ j= 0;
+ for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
+ {
+ pb_nr= pcidev[devind].pd_bar[i].pb_nr;
+ if ((pb_nr == 0 || pb_nr == 1) && clear_01)
+ {
+ if (debug) printf("skipping bar %d\n", pb_nr);
+ continue; /* Skip */
+ }
+ if ((pb_nr == 2 || pb_nr == 3) && clear_23)
+ {
+ if (debug) printf("skipping bar %d\n", pb_nr);
+ continue; /* Skip */
+ }
+ if (i == j)
+ {
+ j++;
+ continue; /* No need to copy */
+ }
+ pcidev[devind].pd_bar[j]=
+ pcidev[devind].pd_bar[i];
+ j++;
+ }
+ pcidev[devind].pd_bar_nr= j;
+ }
+}
+
+static void
+record_bars_bridge(int devind)
+{
+ u32_t base, limit, size;
+
+ /* The generic BAR area of PCI-to-PCI bridges is two DWORDs in size.
+ * It may contain up to two 32-bit BARs, or one 64-bit BAR.
+ */
+ record_bars(devind, PCI_BAR_2);
+
+ base= ((__pci_attr_r8(devind, PPB_IOBASE) & PPB_IOB_MASK) << 8) |
+ (__pci_attr_r16(devind, PPB_IOBASEU16) << 16);
+ limit= 0xff |
+ ((__pci_attr_r8(devind, PPB_IOLIMIT) & PPB_IOL_MASK) << 8) |
+ ((~PPB_IOL_MASK & 0xff) << 8) |
+ (__pci_attr_r16(devind, PPB_IOLIMITU16) << 16);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tI/O window: base 0x%x, limit 0x%x, size %d\n",
+ base, limit, size);
+ }
+
+ base= ((__pci_attr_r16(devind, PPB_MEMBASE) & PPB_MEMB_MASK) << 16);
+ limit= 0xffff |
+ ((__pci_attr_r16(devind, PPB_MEMLIMIT) & PPB_MEML_MASK) << 16) |
+ ((~PPB_MEML_MASK & 0xffff) << 16);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tMemory window: base 0x%x, limit 0x%x, size 0x%x\n",
+ base, limit, size);
+ }
+
+ /* Ignore the upper 32 bits */
+ base= ((__pci_attr_r16(devind, PPB_PFMEMBASE) & PPB_PFMEMB_MASK) << 16);
+ limit= 0xffff |
+ ((__pci_attr_r16(devind, PPB_PFMEMLIMIT) &
+ PPB_PFMEML_MASK) << 16) |
+ ((~PPB_PFMEML_MASK & 0xffff) << 16);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf(
+ "\tPrefetchable memory window: base 0x%x, limit 0x%x, size 0x%x\n",
+ base, limit, size);
+ }
}
-/*===========================================================================*
- * complete_bridges *
- *===========================================================================*/
-static void complete_bridges()
+static void
+record_bars_cardbus(int devind)
{
- int i, freebus, devind, prim_busnr;
-
- for (i= 0; i<nr_pcibus; i++)
- {
- if (!pcibus[i].pb_needinit)
- continue;
- printf("should allocate bus number for bus %d\n", i);
- freebus= get_freebus();
- printf("got bus number %d\n", freebus);
-
- devind= pcibus[i].pb_devind;
+ u32_t base, limit, size;
- prim_busnr= pcidev[devind].pd_busnr;
- if (prim_busnr != 0)
- {
- printf(
- "complete_bridge: updating subordinate bus number not implemented\n");
- }
+ /* The generic BAR area of CardBus devices is one DWORD in size. */
+ record_bars(devind, PCI_BAR);
- pcibus[i].pb_needinit= 0;
- pcibus[i].pb_busnr= freebus;
+ base= __pci_attr_r32(devind, CBB_MEMBASE_0);
+ limit= __pci_attr_r32(devind, CBB_MEMLIMIT_0) |
+ (~CBB_MEML_MASK & 0xffffffff);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tMemory window 0: base 0x%x, limit 0x%x, size %d\n",
+ base, limit, size);
+ }
- printf("devind = %d\n", devind);
- printf("prim_busnr= %d\n", prim_busnr);
+ base= __pci_attr_r32(devind, CBB_MEMBASE_1);
+ limit= __pci_attr_r32(devind, CBB_MEMLIMIT_1) |
+ (~CBB_MEML_MASK & 0xffffffff);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tMemory window 1: base 0x%x, limit 0x%x, size %d\n",
+ base, limit, size);
+ }
- pci_attr_w8(devind, PPB_PRIMBN, prim_busnr);
- pci_attr_w8(devind, PPB_SECBN, freebus);
- pci_attr_w8(devind, PPB_SUBORDBN, freebus);
+ base= __pci_attr_r32(devind, CBB_IOBASE_0);
+ limit= __pci_attr_r32(devind, CBB_IOLIMIT_0) |
+ (~CBB_IOL_MASK & 0xffffffff);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tI/O window 0: base 0x%x, limit 0x%x, size %d\n",
+ base, limit, size);
+ }
- printf("CR = 0x%x\n", pci_attr_r16(devind, PCI_CR));
- printf("SECBLT = 0x%x\n", pci_attr_r8_u(devind, PPB_SECBLT));
- printf("BRIDGECTRL = 0x%x\n",
- pci_attr_r16(devind, PPB_BRIDGECTRL));
+ base= __pci_attr_r32(devind, CBB_IOBASE_1);
+ limit= __pci_attr_r32(devind, CBB_IOLIMIT_1) |
+ (~CBB_IOL_MASK & 0xffffffff);
+ size= limit-base + 1;
+ if (debug)
+ {
+ printf("\tI/O window 1: base 0x%x, limit 0x%x, size %d\n",
+ base, limit, size);
}
}
-/*===========================================================================*
- * complete_bars *
- *===========================================================================*/
-static void complete_bars(void)
+static void
+complete_bars(void)
{
int i, j, bar_nr, reg;
u32_t memgap_low, memgap_high, iogap_low, iogap_high, io_high,
memgap_high= base;
bar_nr= pcidev[i].pd_bar[j].pb_nr;
reg= PCI_BAR + 4*bar_nr;
- v32= pci_attr_r32_u(i, reg);
- pci_attr_w32(i, reg, v32 | base);
+ v32= __pci_attr_r32(i, reg);
+ __pci_attr_w32(i, reg, v32 | base);
if (debug)
{
printf(
iogap_high= base;
bar_nr= pcidev[i].pd_bar[j].pb_nr;
reg= PCI_BAR + 4*bar_nr;
- v32= pci_attr_r32_u(i, reg);
- pci_attr_w32(i, reg, v32 | base);
+ v32= __pci_attr_r32(i, reg);
+ __pci_attr_w32(i, reg, v32 | base);
if (debug)
{
printf(
}
/*===========================================================================*
- * update_bridge4dev_io *
+ * PCI Bridge Helpers *
*===========================================================================*/
-static void update_bridge4dev_io(
- int devind,
- u32_t io_base,
- u32_t io_size
-)
+static void
+probe_bus(int busind)
{
- int busnr, busind, type, br_devind;
- u16_t v16;
-
- busnr= pcidev[devind].pd_busnr;
- busind= get_busind(busnr);
- type= pcibus[busind].pb_type;
- if (type == PBT_INTEL_HOST)
- return; /* Nothing to do for host controller */
- if (type == PBT_PCIBRIDGE)
- {
- printf(
- "update_bridge4dev_io: not implemented for PCI bridges\n");
- return;
- }
- if (type != PBT_CARDBUS)
- panic("update_bridge4dev_io: strange bus type: %d", type);
+ u32_t dev, func, t3;
+ u16_t vid, did, sts, sub_vid, sub_did;
+ u8_t headt;
+ u8_t baseclass, subclass, infclass;
+ int devind, busnr;
+ const char *s, *dstr;
if (debug)
+ printf("probe_bus(%d)\n", busind);
+ if (nr_pcidev >= NR_PCIDEV)
+ panic("too many PCI devices: %d", nr_pcidev);
+ devind= nr_pcidev;
+
+ busnr= pcibus[busind].pb_busnr;
+ for (dev= 0; dev<32; dev++)
{
- printf("update_bridge4dev_io: adding 0x%x at 0x%x\n",
- io_size, io_base);
+
+ for (func= 0; func < 8; func++)
+ {
+ pcidev[devind].pd_busnr= busnr;
+ pcidev[devind].pd_dev= dev;
+ pcidev[devind].pd_func= func;
+
+ pci_attr_wsts(devind,
+ PSR_SSE|PSR_RMAS|PSR_RTAS);
+ vid= __pci_attr_r16(devind, PCI_VID);
+ did= __pci_attr_r16(devind, PCI_DID);
+ headt= __pci_attr_r8(devind, PCI_HEADT);
+ sts= pci_attr_rsts(devind);
+
+#if 0
+ printf("vid 0x%x, did 0x%x, headt 0x%x, sts 0x%x\n",
+ vid, did, headt, sts);
+#endif
+
+ if (vid == NO_VID && did == NO_VID)
+ {
+ if (func == 0)
+ break; /* Nothing here */
+
+ /* Scan all functions of a multifunction
+ * device.
+ */
+ continue;
+ }
+
+ if (sts & (PSR_SSE|PSR_RMAS|PSR_RTAS))
+ {
+ static int warned = 0;
+
+ if(!warned) {
+ printf(
+ "PCI: ignoring bad value 0x%x in sts for QEMU\n",
+ sts & (PSR_SSE|PSR_RMAS|PSR_RTAS));
+ warned = 1;
+ }
+ }
+
+ sub_vid= __pci_attr_r16(devind, PCI_SUBVID);
+ sub_did= __pci_attr_r16(devind, PCI_SUBDID);
+
+ dstr= _pci_dev_name(vid, did);
+ if (debug)
+ {
+ if (dstr)
+ {
+ printf("%d.%lu.%lu: %s (%04X:%04X)\n",
+ busnr, (unsigned long)dev,
+ (unsigned long)func, dstr,
+ vid, did);
+ }
+ else
+ {
+ printf(
+ "%d.%lu.%lu: Unknown device, vendor %04X (%s), device %04X\n",
+ busnr, (unsigned long)dev,
+ (unsigned long)func, vid,
+ pci_vid_name(vid), did);
+ }
+ printf("Device index: %d\n", devind);
+ printf("Subsystem: Vid 0x%x, did 0x%x\n",
+ sub_vid, sub_did);
+ }
+
+ baseclass= __pci_attr_r8(devind, PCI_BCR);
+ subclass= __pci_attr_r8(devind, PCI_SCR);
+ infclass= __pci_attr_r8(devind, PCI_PIFR);
+ s= pci_subclass_name(baseclass, subclass, infclass);
+ if (!s)
+ s= pci_baseclass_name(baseclass);
+ {
+ if (!s)
+ s= "(unknown class)";
+ }
+ if (debug)
+ {
+ printf("\tclass %s (%X/%X/%X)\n", s,
+ baseclass, subclass, infclass);
+ }
+
+ if (is_duplicate(busnr, dev, func))
+ {
+ printf("\tduplicate!\n");
+ if (func == 0 && !(headt & PHT_MULTIFUNC))
+ break;
+ continue;
+ }
+
+ devind= nr_pcidev;
+ nr_pcidev++;
+ pcidev[devind].pd_baseclass= baseclass;
+ pcidev[devind].pd_subclass= subclass;
+ pcidev[devind].pd_infclass= infclass;
+ pcidev[devind].pd_vid= vid;
+ pcidev[devind].pd_did= did;
+ pcidev[devind].pd_sub_vid= sub_vid;
+ pcidev[devind].pd_sub_did= sub_did;
+ pcidev[devind].pd_inuse= 0;
+ pcidev[devind].pd_bar_nr= 0;
+ record_irq(devind);
+ switch(headt & PHT_MASK)
+ {
+ case PHT_NORMAL:
+ record_bars_normal(devind);
+ break;
+ case PHT_BRIDGE:
+ record_bars_bridge(devind);
+ break;
+ case PHT_CARDBUS:
+ record_bars_cardbus(devind);
+ break;
+ default:
+ printf("\t%d.%d.%d: unknown header type %d\n",
+ busind, dev, func,
+ headt & PHT_MASK);
+ break;
+ }
+ if (debug)
+ print_capabilities(devind);
+
+ t3= ((baseclass << 16) | (subclass << 8) | infclass);
+#if 0
+ if (t3 == PCI_T3_VGA || t3 == PCI_T3_VGA_OLD)
+ report_vga(devind);
+#endif
+
+ if (nr_pcidev >= NR_PCIDEV)
+ panic("too many PCI devices: %d", nr_pcidev);
+ devind= nr_pcidev;
+
+ if (func == 0 && !(headt & PHT_MULTIFUNC))
+ break;
+ }
}
- br_devind= pcibus[busind].pb_devind;
- pci_attr_w32(br_devind, CBB_IOLIMIT_0, io_base+io_size-1);
- pci_attr_w32(br_devind, CBB_IOBASE_0, io_base);
+}
- /* Enable I/O access. Enable busmaster access as well. */
- v16= pci_attr_r16(devind, PCI_CR);
- pci_attr_w16(devind, PCI_CR, v16 | PCI_CR_IO_EN | PCI_CR_MAST_EN);
+
+static u16_t
+pcibr_std_rsts(int busind)
+{
+ int devind;
+
+ devind= pcibus[busind].pb_devind;
+ return __pci_attr_r16(devind, PPB_SSTS);
}
-/*===========================================================================*
- * get_freebus *
- *===========================================================================*/
-static int get_freebus()
+static void
+pcibr_std_wsts(int busind, u16_t value)
{
- int i, freebus;
+ int devind;
+ devind= pcibus[busind].pb_devind;
- freebus= 1;
- for (i= 0; i<nr_pcibus; i++)
- {
- if (pcibus[i].pb_needinit)
- continue;
- if (pcibus[i].pb_type == PBT_INTEL_HOST)
- continue;
- if (pcibus[i].pb_busnr <= freebus)
- freebus= pcibus[i].pb_busnr+1;
- printf("get_freebus: should check suboridinate bus number\n");
- }
- return freebus;
+#if 0
+ printf("pcibr_std_wsts(%d, 0x%X), devind= %d\n",
+ busind, value, devind);
+#endif
+ __pci_attr_w16(devind, PPB_SSTS, value);
+}
+
+static u16_t
+pcibr_cb_rsts(int busind)
+{
+ int devind;
+ devind= pcibus[busind].pb_devind;
+
+ return __pci_attr_r16(devind, CBB_SSTS);
+}
+
+static void
+pcibr_cb_wsts(int busind, u16_t value)
+{
+ int devind;
+ devind= pcibus[busind].pb_devind;
+
+#if 0
+ printf("pcibr_cb_wsts(%d, 0x%X), devind= %d\n",
+ busind, value, devind);
+#endif
+ __pci_attr_w16(devind, CBB_SSTS, value);
+}
+
+static u16_t
+pcibr_via_rsts(int busind)
+{
+ return 0;
}
-/*===========================================================================*
- * do_isabridge *
- *===========================================================================*/
-static int do_isabridge(busind)
-int busind;
+static void
+pcibr_via_wsts(int busind, u16_t value)
{
- int i, j, r, type, busnr, unknown_bridge, bridge_dev;
- u16_t vid, did;
- u32_t t3;
- char *dstr;
+ int devind;
+ devind= pcibus[busind].pb_devind;
- unknown_bridge= -1;
- bridge_dev= -1;
- j= 0; /* lint */
- vid= did= 0; /* lint */
- busnr= pcibus[busind].pb_busnr;
- for (i= 0; i< nr_pcidev; i++)
+#if 0
+ printf("pcibr_via_wsts(%d, 0x%X), devind= %d (not implemented)\n",
+ busind, value, devind);
+#endif
+}
+
+static void
+complete_bridges(void)
+{
+ int i, freebus, devind, prim_busnr;
+
+ for (i= 0; i<nr_pcibus; i++)
{
- if (pcidev[i].pd_busnr != busnr)
+ if (!pcibus[i].pb_needinit)
continue;
- t3= ((pcidev[i].pd_baseclass << 16) |
- (pcidev[i].pd_subclass << 8) | pcidev[i].pd_infclass);
- if (t3 == PCI_T3_ISA)
- {
- /* ISA bridge. Report if no supported bridge is
- * found.
- */
- unknown_bridge= i;
- }
+ printf("should allocate bus number for bus %d\n", i);
+ freebus= get_freebus();
+ printf("got bus number %d\n", freebus);
- vid= pcidev[i].pd_vid;
- did= pcidev[i].pd_did;
- for (j= 0; pci_isabridge[j].vid != 0; j++)
- {
- if (pci_isabridge[j].vid != vid)
- continue;
- if (pci_isabridge[j].did != did)
- continue;
- if (pci_isabridge[j].checkclass &&
- unknown_bridge != i)
- {
- /* This part of multifunction device is
- * not the bridge.
- */
- continue;
- }
- break;
- }
- if (pci_isabridge[j].vid)
- {
- bridge_dev= i;
- break;
- }
- }
+ devind= pcibus[i].pb_devind;
- if (bridge_dev != -1)
- {
- dstr= pci_dev_name(vid, did);
- if (!dstr)
- dstr= "unknown device";
- if (debug)
- {
- printf("found ISA bridge (%04X:%04X) %s\n",
- vid, did, dstr);
- }
- pcibus[busind].pb_isabridge_dev= bridge_dev;
- type= pci_isabridge[j].type;
- pcibus[busind].pb_isabridge_type= type;
- switch(type)
+ prim_busnr= pcidev[devind].pd_busnr;
+ if (prim_busnr != 0)
{
- case PCI_IB_PIIX:
- r= do_piix(bridge_dev);
- break;
- case PCI_IB_VIA:
- r= do_via_isabr(bridge_dev);
- break;
- case PCI_IB_AMD:
- r= do_amd_isabr(bridge_dev);
- break;
- case PCI_IB_SIS:
- r= do_sis_isabr(bridge_dev);
- break;
- default:
- panic("unknown ISA bridge type: %d", type);
+ printf(
+ "complete_bridge: updating subordinate bus number not implemented\n");
}
- return r;
- }
- if (unknown_bridge == -1)
- {
- if (debug)
- {
- printf("(warning) no ISA bridge found on bus %d\n",
- busind);
- }
- return 0;
- }
- if (debug)
- {
- printf(
- "(warning) unsupported ISA bridge %04X:%04X for bus %d\n",
- pcidev[unknown_bridge].pd_vid,
- pcidev[unknown_bridge].pd_did, busind);
+ pcibus[i].pb_needinit= 0;
+ pcibus[i].pb_busnr= freebus;
+
+ printf("devind = %d\n", devind);
+ printf("prim_busnr= %d\n", prim_busnr);
+
+ __pci_attr_w8(devind, PPB_PRIMBN, prim_busnr);
+ __pci_attr_w8(devind, PPB_SECBN, freebus);
+ __pci_attr_w8(devind, PPB_SUBORDBN, freebus);
+
+ printf("CR = 0x%x\n", __pci_attr_r16(devind, PCI_CR));
+ printf("SECBLT = 0x%x\n", __pci_attr_r8(devind, PPB_SECBLT));
+ printf("BRIDGECTRL = 0x%x\n",
+ __pci_attr_r16(devind, PPB_BRIDGECTRL));
}
- return 0;
}
/*
* (pbnr) must be already known to acpi and it must map dev as the connection to
* the secondary (sbnr) bus
*/
-static void acpi_map_bridge(unsigned pbnr, unsigned dev, unsigned sbnr)
+static void
+acpi_map_bridge(unsigned int pbnr, unsigned int dev, unsigned int sbnr)
{
int err;
message m;
pbnr, sbnr);
}
-/*===========================================================================*
- * do_pcibridge *
- *===========================================================================*/
-static void do_pcibridge(busind)
-int busind;
+static void
+do_pcibridge(int busind)
{
int i, devind, busnr;
int ind, type;
{
#if 0
printf("do_pcibridge: trying %u.%u.%u\n",
- pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
+ pcidev[devind].pd_busnr, pcidev[devind].pd_dev,
pcidev[devind].pd_func);
#endif
type= pci_pcibridge[i].type;
if (pci_pcibridge[i].vid == 0)
{
- headt= pci_attr_r8_u(devind, PCI_HEADT);
+ headt= __pci_attr_r8(devind, PCI_HEADT);
type= 0;
if ((headt & PHT_MASK) == PHT_BRIDGE)
type= PCI_PPB_STD;
continue; /* Not a bridge */
}
- baseclass= pci_attr_r8_u(devind, PCI_BCR);
- subclass= pci_attr_r8_u(devind, PCI_SCR);
- infclass= pci_attr_r8_u(devind, PCI_PIFR);
+ baseclass= __pci_attr_r8(devind, PCI_BCR);
+ subclass= __pci_attr_r8(devind, PCI_SCR);
+ infclass= __pci_attr_r8(devind, PCI_PIFR);
t3= ((baseclass << 16) | (subclass << 8) | infclass);
if (type == PCI_PPB_STD &&
t3 != PCI_T3_PCI2PCI &&
baseclass, subclass, infclass,
vid, did);
continue;
- }
+ }
if (type == PCI_PPB_CB &&
t3 != PCI_T3_CARDBUS)
{
baseclass, subclass, infclass,
vid, did);
continue;
- }
+ }
}
if (debug)
{
printf("%u.%u.%u: PCI-to-PCI bridge: %04X:%04X\n",
pcidev[devind].pd_busnr,
- pcidev[devind].pd_dev,
+ pcidev[devind].pd_dev,
pcidev[devind].pd_func, vid, did);
}
/* Assume that the BIOS initialized the secondary bus
* number.
*/
- sbusn= pci_attr_r8_u(devind, PPB_SECBN);
+ sbusn= __pci_attr_r8(devind, PPB_SECBN);
if (nr_pcibus >= NR_PCIBUS)
panic("too many PCI busses: %d", nr_pcibus);
pcibus[ind].pb_wsts= pcibr_via_wsts;
break;
default:
- panic("unknown PCI-PCI bridge type: %d", type);
+ panic("unknown PCI-PCI bridge type: %d", type);
}
if (machine.apic_enabled)
- acpi_map_bridge(pcidev[devind].pd_busnr,
- pcidev[devind].pd_dev, sbusn);
-
- if (debug)
- {
- printf(
- "bus(table) = %d, bus(sec) = %d, bus(subord) = %d\n",
- ind, sbusn, pci_attr_r8_u(devind, PPB_SUBORDBN));
- }
- if (sbusn == 0)
- {
- printf("Secondary bus number not initialized\n");
- continue;
- }
- pcibus[ind].pb_needinit= 0;
-
- probe_bus(ind);
-
- /* Look for PCI bridges */
- do_pcibridge(ind);
- }
-}
-
-/*===========================================================================*
- * get_busind *
- *===========================================================================*/
-static int get_busind(busnr)
-int busnr;
-{
- int i;
-
- for (i= 0; i<nr_pcibus; i++)
- {
- if (pcibus[i].pb_busnr == busnr)
- return i;
- }
- panic("get_busind: can't find bus: %d", busnr);
-}
-
-/*===========================================================================*
- * do_piix *
- *===========================================================================*/
-static int do_piix(int devind)
-{
- int i, s, irqrc, irq;
- u32_t elcr1, elcr2, elcr;
-
-#if DEBUG
- printf("in piix\n");
-#endif
- if (OK != (s=sys_inb(PIIX_ELCR1, &elcr1)))
- printf("Warning, sys_inb failed: %d\n", s);
- if (OK != (s=sys_inb(PIIX_ELCR2, &elcr2)))
- printf("Warning, sys_inb failed: %d\n", s);
- elcr= elcr1 | (elcr2 << 8);
- for (i= 0; i<4; i++)
- {
- irqrc= pci_attr_r8_u(devind, PIIX_PIRQRCA+i);
- if (irqrc & PIIX_IRQ_DI)
- {
- if (debug)
- printf("INT%c: disabled\n", 'A'+i);
- }
- else
- {
- irq= irqrc & PIIX_IRQ_MASK;
- if (debug)
- printf("INT%c: %d\n", 'A'+i, irq);
- if (!(elcr & (1 << irq)))
- {
- if (debug)
- {
- printf(
- "(warning) IRQ %d is not level triggered\n",
- irq);
- }
- }
- irq_mode_pci(irq);
- }
- }
- return 0;
-}
-
-/*===========================================================================*
- * do_amd_isabr *
- *===========================================================================*/
-static int do_amd_isabr(int devind)
-{
- int i, busnr, dev, func, xdevind, irq, edge;
- u8_t levmask;
- u16_t pciirq;
-
- /* Find required function */
- func= AMD_ISABR_FUNC;
- busnr= pcidev[devind].pd_busnr;
- dev= pcidev[devind].pd_dev;
-
- /* Fake a device with the required function */
- if (nr_pcidev >= NR_PCIDEV)
- panic("too many PCI devices: %d", nr_pcidev);
- xdevind= nr_pcidev;
- pcidev[xdevind].pd_busnr= busnr;
- pcidev[xdevind].pd_dev= dev;
- pcidev[xdevind].pd_func= func;
- pcidev[xdevind].pd_inuse= 1;
- nr_pcidev++;
-
- levmask= pci_attr_r8_u(xdevind, AMD_ISABR_PCIIRQ_LEV);
- pciirq= pci_attr_r16(xdevind, AMD_ISABR_PCIIRQ_ROUTE);
- for (i= 0; i<4; i++)
- {
- edge= (levmask >> i) & 1;
- irq= (pciirq >> (4*i)) & 0xf;
- if (!irq)
- {
- if (debug)
- printf("INT%c: disabled\n", 'A'+i);
- }
- else
- {
- if (debug)
- printf("INT%c: %d\n", 'A'+i, irq);
- if (edge && debug)
- {
- printf(
- "(warning) IRQ %d is not level triggered\n",
- irq);
- }
- irq_mode_pci(irq);
- }
- }
- nr_pcidev--;
- return 0;
-}
-
-/*===========================================================================*
- * do_sis_isabr *
- *===========================================================================*/
-static int do_sis_isabr(int devind)
-{
- int i, irq;
-
- irq= 0; /* lint */
- for (i= 0; i<4; i++)
- {
- irq= pci_attr_r8_u(devind, SIS_ISABR_IRQ_A+i);
- if (irq & SIS_IRQ_DISABLED)
+ acpi_map_bridge(pcidev[devind].pd_busnr,
+ pcidev[devind].pd_dev, sbusn);
+
+ if (debug)
{
- if (debug)
- printf("INT%c: disabled\n", 'A'+i);
+ printf(
+ "bus(table) = %d, bus(sec) = %d, bus(subord) = %d\n",
+ ind, sbusn, __pci_attr_r8(devind, PPB_SUBORDBN));
}
- else
+ if (sbusn == 0)
{
- irq &= SIS_IRQ_MASK;
- if (debug)
- printf("INT%c: %d\n", 'A'+i, irq);
- irq_mode_pci(irq);
+ printf("Secondary bus number not initialized\n");
+ continue;
}
+ pcibus[ind].pb_needinit= 0;
+
+ probe_bus(ind);
+
+ /* Look for PCI bridges */
+ do_pcibridge(ind);
}
- return 0;
}
/*===========================================================================*
- * do_via_isabr *
+ * pci_intel_init *
*===========================================================================*/
-static int do_via_isabr(int devind)
+static void
+pci_intel_init()
{
- int i, irq, edge;
- u8_t levmask;
+ /* Try to detect a know PCI controller. Read the Vendor ID and
+ * the Device ID for function 0 of device 0.
+ * Two times the value 0xffff suggests a system without a (compatible)
+ * PCI controller.
+ */
+ u32_t bus, dev, func;
+ u16_t vid, did;
+ int s, i, r, busind, busnr;
+ const char *dstr;
- levmask= pci_attr_r8_u(devind, VIA_ISABR_EL);
- irq= 0; /* lint */
- edge= 0; /* lint */
- for (i= 0; i<4; i++)
+ bus= 0;
+ dev= 0;
+ func= 0;
+
+ vid= PCII_RREG16_(bus, dev, func, PCI_VID);
+ did= PCII_RREG16_(bus, dev, func, PCI_DID);
+ if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
+ printf("PCI: warning, sys_outl failed: %d\n", s);
+
+#if 0
+ if (vid == 0xffff && did == 0xffff)
+ return; /* Nothing here */
+
+ for (i= 0; pci_intel_ctrl[i].vid; i++)
{
- switch(i)
+ if (pci_intel_ctrl[i].vid == vid &&
+ pci_intel_ctrl[i].did == did)
{
- case 0:
- edge= (levmask & VIA_ISABR_EL_INTA);
- irq= pci_attr_r8_u(devind, VIA_ISABR_IRQ_R2) >> 4;
- break;
- case 1:
- edge= (levmask & VIA_ISABR_EL_INTB);
- irq= pci_attr_r8_u(devind, VIA_ISABR_IRQ_R2);
- break;
- case 2:
- edge= (levmask & VIA_ISABR_EL_INTC);
- irq= pci_attr_r8_u(devind, VIA_ISABR_IRQ_R3) >> 4;
- break;
- case 3:
- edge= (levmask & VIA_ISABR_EL_INTD);
- irq= pci_attr_r8_u(devind, VIA_ISABR_IRQ_R1) >> 4;
break;
- default:
- assert(0);
- }
- irq &= 0xf;
- if (!irq)
- {
- if (debug)
- printf("INT%c: disabled\n", 'A'+i);
}
- else
+ }
+
+ if (!pci_intel_ctrl[i].vid)
+ {
+ printf("pci_intel_init (warning): unknown PCI-controller:\n"
+ "\tvendor %04X (%s), device %04X\n",
+ vid, pci_vid_name(vid), did);
+ }
+#endif
+
+ if (nr_pcibus >= NR_PCIBUS)
+ panic("too many PCI busses: %d", nr_pcibus);
+ busind= nr_pcibus;
+ nr_pcibus++;
+ pcibus[busind].pb_type= PBT_INTEL_HOST;
+ pcibus[busind].pb_needinit= 0;
+ pcibus[busind].pb_isabridge_dev= -1;
+ pcibus[busind].pb_isabridge_type= 0;
+ pcibus[busind].pb_devind= -1;
+ pcibus[busind].pb_busnr= 0;
+ pcibus[busind].pb_rreg8= pcii_rreg8;
+ pcibus[busind].pb_rreg16= pcii_rreg16;
+ pcibus[busind].pb_rreg32= pcii_rreg32;
+ pcibus[busind].pb_wreg8= pcii_wreg8;
+ pcibus[busind].pb_wreg16= pcii_wreg16;
+ pcibus[busind].pb_wreg32= pcii_wreg32;
+ pcibus[busind].pb_rsts= pcii_rsts;
+ pcibus[busind].pb_wsts= pcii_wsts;
+
+ dstr= _pci_dev_name(vid, did);
+ if (!dstr)
+ dstr= "unknown device";
+ if (debug)
+ {
+ printf("pci_intel_init: %s (%04X:%04X)\n",
+ dstr, vid, did);
+ }
+
+ probe_bus(busind);
+
+ r= do_isabridge(busind);
+ if (r != OK)
+ {
+ busnr= pcibus[busind].pb_busnr;
+
+ /* Disable all devices for this bus */
+ for (i= 0; i<nr_pcidev; i++)
{
- if (debug)
- printf("INT%c: %d\n", 'A'+i, irq);
- if (edge && debug)
- {
- printf(
- "(warning) IRQ %d is not level triggered\n",
- irq);
- }
- irq_mode_pci(irq);
+ if (pcidev[i].pd_busnr != busnr)
+ continue;
+ pcidev[i].pd_inuse= 1;
}
+ return;
}
- return 0;
-}
+ /* Look for PCI bridges */
+ do_pcibridge(busind);
+
+ /* Allocate bus numbers for uninitialized bridges */
+ complete_bridges();
+
+ /* Allocate I/O and memory resources for uninitialized devices */
+ complete_bars();
+}
#if 0
/*===========================================================================*
* report_vga *
*===========================================================================*/
-static void report_vga(devind)
-int devind;
+static void
+report_vga(int devind)
{
/* Report the amount of video memory. This is needed by the X11R6
* postinstall script to chmem the X server. Hopefully this can be
/*===========================================================================*
- * pci_vid_name *
- *===========================================================================*/
-static char *pci_vid_name(u16_t vid)
-{
- int i;
-
- for (i= 0; pci_vendor_table[i].name; i++)
- {
- if (pci_vendor_table[i].vid == vid)
- return pci_vendor_table[i].name;
- }
- return "unknown";
-}
-
-/*===========================================================================*
- * pci_baseclass_name *
+ * visible *
*===========================================================================*/
-static char *pci_baseclass_name(u8_t baseclass)
+static int
+visible(struct rs_pci *aclp, int devind)
{
+ u16_t acl_sub_vid, acl_sub_did;
int i;
+ u32_t class_id;
- for (i= 0; pci_baseclass_table[i].name; i++)
+ if (!aclp)
+ return TRUE; /* Should be changed when ACLs become
+ * mandatory. Do note that procfs relies
+ * on being able to see all devices.
+ */
+ /* Check whether the caller is allowed to get this device. */
+ for (i= 0; i<aclp->rsp_nr_device; i++)
{
- if (pci_baseclass_table[i].baseclass == baseclass)
- return pci_baseclass_table[i].name;
+ acl_sub_vid = aclp->rsp_device[i].sub_vid;
+ acl_sub_did = aclp->rsp_device[i].sub_did;
+ if (aclp->rsp_device[i].vid == pcidev[devind].pd_vid &&
+ aclp->rsp_device[i].did == pcidev[devind].pd_did &&
+ (acl_sub_vid == NO_SUB_VID ||
+ acl_sub_vid == pcidev[devind].pd_sub_vid) &&
+ (acl_sub_did == NO_SUB_DID ||
+ acl_sub_did == pcidev[devind].pd_sub_did))
+ {
+ return TRUE;
+ }
}
- return NULL;
-}
-
-/*===========================================================================*
- * pci_subclass_name *
- *===========================================================================*/
-static char *pci_subclass_name(u8_t baseclass, u8_t subclass, u8_t infclass)
-{
- int i;
+ if (!aclp->rsp_nr_class)
+ return FALSE;
- for (i= 0; pci_subclass_table[i].name; i++)
+ class_id= (pcidev[devind].pd_baseclass << 16) |
+ (pcidev[devind].pd_subclass << 8) |
+ pcidev[devind].pd_infclass;
+ for (i= 0; i<aclp->rsp_nr_class; i++)
{
- if (pci_subclass_table[i].baseclass != baseclass)
- continue;
- if (pci_subclass_table[i].subclass != subclass)
- continue;
- if (pci_subclass_table[i].infclass != infclass &&
- pci_subclass_table[i].infclass != (u16_t)-1)
+ if (aclp->rsp_class[i].pciclass ==
+ (class_id & aclp->rsp_class[i].mask))
{
- continue;
+ return TRUE;
}
- return pci_subclass_table[i].name;
}
- return NULL;
+
+ return FALSE;
}
/*===========================================================================*
- * ntostr *
+ * sef_cb_init_fresh *
*===========================================================================*/
-static void ntostr(n, str, end)
-unsigned n;
-char **str;
-const char *end;
+int
+sef_cb_init_fresh(int type, sef_init_info_t *info)
{
- char tmpstr[20];
- int i;
+/* Initialize the pci driver. */
+ long v;
+ int i, r;
+ struct rprocpub rprocpub[NR_BOOT_PROCS];
- if (n == 0)
- {
- tmpstr[0]= '0';
- i= 1;
+ v= 0;
+ env_parse("pci_debug", "d", 0, &v, 0, 1);
+ debug= v;
+
+ if (sys_getmachine(&machine)) {
+ printf("PCI: no machine\n");
+ return ENODEV;
}
- else
- {
- for (i= 0; n; i++)
- {
- tmpstr[i]= '0' + (n%10);
- n /= 10;
- }
+ if (machine.apic_enabled &&
+ ds_retrieve_label_endpt("acpi", &acpi_ep) != OK) {
+ panic("PCI: Cannot use APIC mode without ACPI!\n");
}
- for (; i>0; i--)
- {
- if (*str == end)
- {
- break;
+
+ /* Only Intel (compatible) PCI controllers are supported at the
+ * moment.
+ */
+ pci_intel_init();
+
+ /* Map all the services in the boot image. */
+ if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
+ (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) {
+ panic("sys_safecopyfrom failed: %d", r);
+ }
+ for(i=0;i < NR_BOOT_PROCS;i++) {
+ if(rprocpub[i].in_use) {
+ if((r = map_service(&rprocpub[i])) != OK) {
+ panic("unable to map service: %d", r);
+ }
}
- **str= tmpstr[i-1];
- (*str)++;
}
- if (*str == end)
- (*str)[-1]= '\0';
- else
- **str= '\0';
+
+ return(OK);
}
/*===========================================================================*
- * pci_attr_rsts *
+ * map_service *
*===========================================================================*/
-static u16_t pci_attr_rsts(devind)
-int devind;
+int
+map_service(struct rprocpub *rpub)
{
- int busnr, busind;
+/* Map a new service by registering a new acl entry if required. */
+ int i;
- busnr= pcidev[devind].pd_busnr;
- busind= get_busind(busnr);
- return pcibus[busind].pb_rsts(busind);
-}
-
+ /* Stop right now if no pci device or class is found. */
+ if(rpub->pci_acl.rsp_nr_device == 0
+ && rpub->pci_acl.rsp_nr_class == 0) {
+ return(OK);
+ }
-/*===========================================================================*
- * pcibr_std_rsts *
- *===========================================================================*/
-static u16_t pcibr_std_rsts(busind)
-int busind;
-{
- int devind;
+ /* Find a free acl slot. */
+ for (i= 0; i<NR_DRIVERS; i++)
+ {
+ if (!pci_acl[i].inuse)
+ break;
+ }
+ if (i >= NR_DRIVERS)
+ {
+ printf("PCI: map_service: table is full\n");
+ return ENOMEM;
+ }
- devind= pcibus[busind].pb_devind;
- return pci_attr_r16(devind, PPB_SSTS);
+ /* Initialize acl slot. */
+ pci_acl[i].inuse = 1;
+ pci_acl[i].acl = rpub->pci_acl;
+
+ return(OK);
}
/*===========================================================================*
- * pcibr_std_wsts *
+ * _pci_find_dev *
*===========================================================================*/
-static void pcibr_std_wsts(int busind, u16_t value)
+int
+_pci_find_dev(u8_t bus, u8_t dev, u8_t func, int *devindp)
{
int devind;
- devind= pcibus[busind].pb_devind;
+ for (devind= 0; devind < nr_pcidev; devind++)
+ {
+ if (pcidev[devind].pd_busnr == bus &&
+ pcidev[devind].pd_dev == dev &&
+ pcidev[devind].pd_func == func)
+ {
+ break;
+ }
+ }
+ if (devind >= nr_pcidev)
+ return 0;
#if 0
- printf("pcibr_std_wsts(%d, 0x%X), devind= %d\n",
- busind, value, devind);
+ if (pcidev[devind].pd_inuse)
+ return 0;
#endif
- pci_attr_w16(devind, PPB_SSTS, value);
-}
-
-/*===========================================================================*
- * pcibr_cb_rsts *
- *===========================================================================*/
-static u16_t pcibr_cb_rsts(busind)
-int busind;
-{
- int devind;
- devind= pcibus[busind].pb_devind;
-
- return pci_attr_r16(devind, CBB_SSTS);
+ *devindp= devind;
+ return 1;
}
/*===========================================================================*
- * pcibr_cb_wsts *
+ * _pci_first_dev *
*===========================================================================*/
-static void pcibr_cb_wsts(int busind, u16_t value)
+int
+_pci_first_dev(struct rs_pci *aclp, int *devindp, u16_t *vidp,
+ u16_t *didp)
{
int devind;
- devind= pcibus[busind].pb_devind;
+ for (devind= 0; devind < nr_pcidev; devind++)
+ {
#if 0
- printf("pcibr_cb_wsts(%d, 0x%X), devind= %d\n",
- busind, value, devind);
+ if (pcidev[devind].pd_inuse)
+ continue;
#endif
- pci_attr_w16(devind, CBB_SSTS, value);
-}
-
-/*===========================================================================*
- * pcibr_via_rsts *
- *===========================================================================*/
-static u16_t pcibr_via_rsts(int busind)
-{
- return 0;
+ if (!visible(aclp, devind))
+ continue;
+ break;
+ }
+ if (devind >= nr_pcidev)
+ return 0;
+ *devindp= devind;
+ *vidp= pcidev[devind].pd_vid;
+ *didp= pcidev[devind].pd_did;
+ return 1;
}
/*===========================================================================*
- * pcibr_via_wsts *
+ * _pci_next_dev *
*===========================================================================*/
-static void pcibr_via_wsts(int busind, u16_t value)
+int
+_pci_next_dev(struct rs_pci *aclp, int *devindp, u16_t *vidp, u16_t *didp)
{
int devind;
- devind= pcibus[busind].pb_devind;
+ for (devind= *devindp+1; devind < nr_pcidev; devind++)
+ {
#if 0
- printf("pcibr_via_wsts(%d, 0x%X), devind= %d (not implemented)\n",
- busind, value, devind);
+ if (pcidev[devind].pd_inuse)
+ continue;
#endif
+ if (!visible(aclp, devind))
+ continue;
+ break;
+ }
+ if (devind >= nr_pcidev)
+ return 0;
+ *devindp= devind;
+ *vidp= pcidev[devind].pd_vid;
+ *didp= pcidev[devind].pd_did;
+ return 1;
}
/*===========================================================================*
- * pci_attr_wsts *
+ * _pci_reserve *
*===========================================================================*/
-static void pci_attr_wsts(int devind, u16_t value)
+int
+_pci_reserve(int devind, endpoint_t proc, struct rs_pci *aclp)
{
- int busnr, busind;
-
- busnr= pcidev[devind].pd_busnr;
- busind= get_busind(busnr);
- pcibus[busind].pb_wsts(busind, value);
-}
-
+ int i, r;
+ int ilr;
+ struct io_range ior;
+ struct minix_mem_range mr;
-/*===========================================================================*
- * pcii_rreg8 *
- *===========================================================================*/
-static u8_t pcii_rreg8(busind, devind, port)
-int busind;
-int devind;
-int port;
-{
- u8_t v;
- int s;
+ if (devind < 0 || devind >= nr_pcidev)
+ {
+ printf("pci_reserve_a: bad devind: %d\n", devind);
+ return EINVAL;
+ }
+ if (!visible(aclp, devind))
+ {
+ printf("pci_reserve_a: %u is not allowed to reserve %d\n",
+ proc, devind);
+ return EPERM;
+ }
- v= PCII_RREG8_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
-#if 0
- printf("pcii_rreg8(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
- busind, devind, port,
- pcibus[busind].pb_bus, pcidev[devind].pd_dev,
- pcidev[devind].pd_func, v);
-#endif
- return v;
-}
+ if(pcidev[devind].pd_inuse && pcidev[devind].pd_proc != proc)
+ return EBUSY;
+ pcidev[devind].pd_inuse= 1;
+ pcidev[devind].pd_proc= proc;
-/*===========================================================================*
- * pcii_rreg16 *
- *===========================================================================*/
-static u16_t pcii_rreg16(int busind, int devind, int port)
-{
- u16_t v;
- int s;
+ for (i= 0; i<pcidev[devind].pd_bar_nr; i++)
+ {
+ if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
+ {
+ printf("pci_reserve_a: BAR %d is incomplete\n", i);
+ continue;
+ }
+ if (pcidev[devind].pd_bar[i].pb_flags & PBF_IO)
+ {
+ ior.ior_base= pcidev[devind].pd_bar[i].pb_base;
+ ior.ior_limit= ior.ior_base +
+ pcidev[devind].pd_bar[i].pb_size-1;
- v= PCII_RREG16_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
-#if 0
- printf("pcii_rreg16(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
- busind, devind, port,
- pcibus[busind].pb_bus, pcidev[devind].pd_dev,
- pcidev[devind].pd_func, v);
-#endif
- return v;
-}
+ if(debug) {
+ printf(
+ "pci_reserve_a: for proc %d, adding I/O range [0x%x..0x%x]\n",
+ proc, ior.ior_base, ior.ior_limit);
+ }
+ r= sys_privctl(proc, SYS_PRIV_ADD_IO, &ior);
+ if (r != OK)
+ {
+ printf("sys_privctl failed for proc %d: %d\n",
+ proc, r);
+ }
+ }
+ else
+ {
+ mr.mr_base= pcidev[devind].pd_bar[i].pb_base;
+ mr.mr_limit= mr.mr_base +
+ pcidev[devind].pd_bar[i].pb_size-1;
-/*===========================================================================*
- * pcii_rreg32 *
- *===========================================================================*/
-static u32_t pcii_rreg32(int busind, int devind, int port)
-{
- u32_t v;
- int s;
+ r= sys_privctl(proc, SYS_PRIV_ADD_MEM, &mr);
+ if (r != OK)
+ {
+ printf("sys_privctl failed for proc %d: %d\n",
+ proc, r);
+ }
+ }
+ }
+ ilr= pcidev[devind].pd_ilr;
+ if (ilr != PCI_ILR_UNKNOWN)
+ {
+ if(debug) printf("pci_reserve_a: adding IRQ %d\n", ilr);
+ r= sys_privctl(proc, SYS_PRIV_ADD_IRQ, &ilr);
+ if (r != OK)
+ {
+ printf("sys_privctl failed for proc %d: %d\n",
+ proc, r);
+ }
+ }
- v= PCII_RREG32_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
-#if 0
- printf("pcii_rreg32(%d, %d, 0x%X): %d.%d.%d= 0x%X\n",
- busind, devind, port,
- pcibus[busind].pb_bus, pcidev[devind].pd_dev,
- pcidev[devind].pd_func, v);
-#endif
- return v;
+ return OK;
}
/*===========================================================================*
- * pcii_wreg8 *
+ * _pci_release *
*===========================================================================*/
-static void pcii_wreg8(
- int busind,
- int devind,
- int port,
- u8_t value
-)
+void
+_pci_release(endpoint_t proc)
{
- int s;
-#if 0
- printf("pcii_wreg8(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
- busind, devind, port, value,
- pcibus[busind].pb_bus, pcidev[devind].pd_dev,
- pcidev[devind].pd_func);
-#endif
- PCII_WREG8_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port, value);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
-}
+ int i;
-/*===========================================================================*
- * pcii_wreg16 *
- *===========================================================================*/
-static void pcii_wreg16(
- int busind,
- int devind,
- int port,
- u16_t value
-)
-{
- int s;
-#if 0
- printf("pcii_wreg16(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
- busind, devind, port, value,
- pcibus[busind].pb_bus, pcidev[devind].pd_dev,
- pcidev[devind].pd_func);
-#endif
- PCII_WREG16_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port, value);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
+ for (i= 0; i<nr_pcidev; i++)
+ {
+ if (!pcidev[i].pd_inuse)
+ continue;
+ if (pcidev[i].pd_proc != proc)
+ continue;
+ pcidev[i].pd_inuse= 0;
+ }
}
/*===========================================================================*
- * pcii_wreg32 *
+ * _pci_ids *
*===========================================================================*/
-static void pcii_wreg32(
- int busind,
- int devind,
- int port,
- u32_t value
-)
+int
+_pci_ids(int devind, u16_t *vidp, u16_t *didp)
{
- int s;
-#if 0
- printf("pcii_wreg32(%d, %d, 0x%X, 0x%X): %d.%d.%d\n",
- busind, devind, port, value,
- pcibus[busind].pb_busnr, pcidev[devind].pd_dev,
- pcidev[devind].pd_func);
-#endif
- PCII_WREG32_(pcibus[busind].pb_busnr,
- pcidev[devind].pd_dev, pcidev[devind].pd_func,
- port, value);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n",s);
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+
+ *vidp= pcidev[devind].pd_vid;
+ *didp= pcidev[devind].pd_did;
+ return OK;
}
/*===========================================================================*
- * pcii_rsts *
+ * _pci_rescan_bus *
*===========================================================================*/
-static u16_t pcii_rsts(int busind)
+void
+_pci_rescan_bus(u8_t busnr)
{
- u16_t v;
- int s;
+ int busind;
- v= PCII_RREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
- return v;
+ busind= get_busind(busnr);
+ probe_bus(busind);
+
+ /* Allocate bus numbers for uninitialized bridges */
+ complete_bridges();
+
+ /* Allocate I/O and memory resources for uninitialized devices */
+ complete_bars();
}
/*===========================================================================*
- * pcii_wsts *
+ * _pci_slot_name *
*===========================================================================*/
-static void pcii_wsts(int busind, u16_t value)
+int
+_pci_slot_name(int devind, char **cpp)
{
- int s;
- PCII_WREG16_(pcibus[busind].pb_busnr, 0, 0, PCI_SR, value);
- if (OK != (s=sys_outl(PCII_CONFADD, PCII_UNSEL)))
- printf("PCI: warning, sys_outl failed: %d\n", s);
-}
+ static char label[]= "ddd.ddd.ddd.ddd";
+ char *end;
+ char *p;
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
-/*===========================================================================*
- * print_capabilities *
- *===========================================================================*/
-static void print_capabilities(int devind)
-{
- u8_t status, capptr, type, next, subtype;
- char *str;
+ p= label;
+ end= label+sizeof(label);
- /* Check capabilities bit in the device status register */
- status= pci_attr_r16(devind, PCI_SR);
- if (!(status & PSR_CAPPTR))
- return;
+ /* FIXME: domain nb is always 0 on 32bit system, but we should
+ * retrieve it properly, somehow. */
+ ntostr(0, &p, end);
+ *p++= '.';
- capptr= (pci_attr_r8_u(devind, PCI_CAPPTR) & PCI_CP_MASK);
- while (capptr != 0)
- {
- type = pci_attr_r8_u(devind, capptr+CAP_TYPE);
- next= (pci_attr_r8_u(devind, capptr+CAP_NEXT) & PCI_CP_MASK);
- switch(type)
- {
- case 1: str= "PCI Power Management"; break;
- case 2: str= "AGP"; break;
- case 3: str= "Vital Product Data"; break;
- case 4: str= "Slot Identification"; break;
- case 5: str= "Message Signaled Interrupts"; break;
- case 6: str= "CompactPCI Hot Swap"; break;
- case 8: str= "AMD HyperTransport"; break;
- case 0xf: str= "Secure Device"; break;
- default: str= "(unknown type)"; break;
- }
+ ntostr(pcidev[devind].pd_busnr, &p, end);
+ *p++= '.';
- printf(" @0x%x (0x%08x): capability type 0x%x: %s",
- capptr, pci_attr_r32_u(devind, capptr), type, str);
- if (type == 0x08)
- print_hyper_cap(devind, capptr);
- else if (type == 0x0f)
- {
- subtype= (pci_attr_r8_u(devind, capptr+2) & 0x07);
- switch(subtype)
- {
- case 0: str= "Device Exclusion Vector"; break;
- case 3: str= "IOMMU"; break;
- default: str= "(unknown type)"; break;
- }
- printf(", sub type 0%o: %s", subtype, str);
- }
- printf("\n");
- capptr= next;
- }
-}
+ ntostr(pcidev[devind].pd_dev, &p, end);
+ *p++= '.';
+
+ ntostr(pcidev[devind].pd_func, &p, end);
+ *cpp= label;
+ return OK;
+}
/*===========================================================================*
- * visible *
+ * _pci_dev_name *
*===========================================================================*/
-static int visible(aclp, devind)
-struct rs_pci *aclp;
-int devind;
+const char *
+_pci_dev_name(u16_t vid, u16_t did)
{
- u16_t acl_sub_vid, acl_sub_did;
int i;
- u32_t class_id;
- if (!aclp)
- return TRUE; /* Should be changed when ACLs become
- * mandatory. Do note that procfs relies
- * on being able to see all devices.
- */
- /* Check whether the caller is allowed to get this device. */
- for (i= 0; i<aclp->rsp_nr_device; i++)
+ for (i= 0; pci_device_table[i].name; i++)
{
- acl_sub_vid = aclp->rsp_device[i].sub_vid;
- acl_sub_did = aclp->rsp_device[i].sub_did;
- if (aclp->rsp_device[i].vid == pcidev[devind].pd_vid &&
- aclp->rsp_device[i].did == pcidev[devind].pd_did &&
- (acl_sub_vid == NO_SUB_VID ||
- acl_sub_vid == pcidev[devind].pd_sub_vid) &&
- (acl_sub_did == NO_SUB_DID ||
- acl_sub_did == pcidev[devind].pd_sub_did))
+ if (pci_device_table[i].vid == vid &&
+ pci_device_table[i].did == did)
{
- return TRUE;
+ return pci_device_table[i].name;
}
}
- if (!aclp->rsp_nr_class)
- return FALSE;
+ return NULL;
+}
- class_id= (pcidev[devind].pd_baseclass << 16) |
- (pcidev[devind].pd_subclass << 8) |
- pcidev[devind].pd_infclass;
- for (i= 0; i<aclp->rsp_nr_class; i++)
+/*===========================================================================*
+ * _pci_get_bar *
+ *===========================================================================*/
+int
+_pci_get_bar(int devind, int port, u32_t *base, u32_t *size,
+ int *ioflag)
+{
+ int i, reg;
+
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+
+ for (i= 0; i < pcidev[devind].pd_bar_nr; i++)
{
- if (aclp->rsp_class[i].pciclass ==
- (class_id & aclp->rsp_class[i].mask))
+ reg= PCI_BAR+4*pcidev[devind].pd_bar[i].pb_nr;
+
+ if (reg == port)
{
- return TRUE;
+ if (pcidev[devind].pd_bar[i].pb_flags & PBF_INCOMPLETE)
+ return EINVAL;
+
+ *base= pcidev[devind].pd_bar[i].pb_base;
+ *size= pcidev[devind].pd_bar[i].pb_size;
+ *ioflag=
+ !!(pcidev[devind].pd_bar[i].pb_flags & PBF_IO);
+ return OK;
}
}
+ return EINVAL;
+}
- return FALSE;
+/*===========================================================================*
+ * _pci_attr_r8 *
+ *===========================================================================*/
+int
+_pci_attr_r8(int devind, int port, u8_t *vp)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-1)
+ return EINVAL;
+
+ *vp= __pci_attr_r8(devind, port);
+ return OK;
}
/*===========================================================================*
- * print_hyper_cap *
+ * _pci_attr_r16 *
*===========================================================================*/
-static void print_hyper_cap(int devind, u8_t capptr)
-{
- u32_t v;
- u16_t cmd;
- int type0, type1;
+int
+_pci_attr_r16(int devind, int port, u16_t *vp)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-2)
+ return EINVAL;
- printf("\n");
- v= pci_attr_r32_u(devind, capptr);
- printf("print_hyper_cap: @0x%x, off 0 (cap):", capptr);
- cmd= (v >> 16) & 0xffff;
-#if 0
- if (v & 0x10000)
- {
- printf(" WarmReset");
- v &= ~0x10000;
- }
- if (v & 0x20000)
- {
- printf(" DblEnded");
- v &= ~0x20000;
- }
- printf(" DevNum %d", (v & 0x7C0000) >> 18);
- v &= ~0x7C0000;
-#endif
- type0= (cmd & 0xE000) >> 13;
- type1= (cmd & 0xF800) >> 11;
- if (type0 == 0 || type0 == 1)
- {
- printf("Capability Type: %s\n",
- type0 == 0 ? "Slave or Primary Interface" :
- "Host or Secondary Interface");
- cmd &= ~0xE000;
- }
- else
- {
- printf(" Capability Type 0x%x", type1);
- cmd &= ~0xF800;
- }
- if (cmd)
- printf(" undecoded 0x%x\n", cmd);
+ *vp= __pci_attr_r16(devind, port);
+ return OK;
+}
-#if 0
- printf("print_hyper_cap: off 4 (ctl): 0x%x\n",
- pci_attr_r32_u(devind, capptr+4));
- printf("print_hyper_cap: off 8 (freq/rev): 0x%x\n",
- pci_attr_r32_u(devind, capptr+8));
- printf("print_hyper_cap: off 12 (cap): 0x%x\n",
- pci_attr_r32_u(devind, capptr+12));
- printf("print_hyper_cap: off 16 (buf count): 0x%x\n",
- pci_attr_r32_u(devind, capptr+16));
- v= pci_attr_r32_u(devind, capptr+20);
- printf("print_hyper_cap: @0x%x, off 20 (bus nr): ",
- capptr+20);
- printf("prim %d", v & 0xff);
- printf(", sec %d", (v >> 8) & 0xff);
- printf(", sub %d", (v >> 16) & 0xff);
- if (v >> 24)
- printf(", reserved %d", (v >> 24) & 0xff);
- printf("\n");
- printf("print_hyper_cap: off 24 (type): 0x%x\n",
- pci_attr_r32_u(devind, capptr+24));
-#endif
+/*===========================================================================*
+ * _pci_attr_r32 *
+ *===========================================================================*/
+int
+_pci_attr_r32(int devind, int port, u32_t *vp)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-4)
+ return EINVAL;
+
+ *vp= __pci_attr_r32(devind, port);
+ return OK;
}
-/*
- * $PchId: pci.c,v 1.7 2003/08/07 09:06:51 philip Exp $
- */
+/*===========================================================================*
+ * _pci_attr_w8 *
+ *===========================================================================*/
+int
+_pci_attr_w8(int devind, int port, u8_t value)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-1)
+ return EINVAL;
+
+ __pci_attr_w8(devind, port, value);
+ return OK;
+}
+
+/*===========================================================================*
+ * _pci_attr_w16 *
+ *===========================================================================*/
+int
+_pci_attr_w16(int devind, int port, u16_t value)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-2)
+ return EINVAL;
+
+ __pci_attr_w16(devind, port, value);
+ return OK;
+}
+
+/*===========================================================================*
+ * _pci_attr_w32 *
+ *===========================================================================*/
+int
+_pci_attr_w32(int devind, int port, u32_t value)
+{
+ if (devind < 0 || devind >= nr_pcidev)
+ return EINVAL;
+ if (port < 0 || port > 256-4)
+ return EINVAL;
+
+ __pci_attr_w32(devind, port, value);
+ return OK;
+}