47351d2774
was needed to make attach/detach of devices work, which is needed for the PCCARD support. (PCCARD support is still not working though, more to come on that) Support the CMD646 chip which is used on many alphas, sadly only in WDMA2 mode, as the silicon is broken beyond belief for UDMA modes. Lots of cosmetic fixes here and there. Sorry for the size of this megapatchfromhell but it was not possible otherwise... newbus patches based on work from: dfr (Doug Rabson)
373 lines
8.2 KiB
C
373 lines
8.2 KiB
C
/*
|
|
* Copyright (c) 1997, Stefan Esser <se@freebsd.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice unmodified, this list of conditions, and the following
|
|
* disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/module.h>
|
|
#include <sys/bus.h>
|
|
#include <machine/bus.h>
|
|
#include <sys/interrupt.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/rman.h>
|
|
|
|
#include <pci/pcivar.h>
|
|
#include <machine/chipset.h>
|
|
#include <machine/cpuconf.h>
|
|
#include <machine/resource.h>
|
|
#include <machine/md_var.h>
|
|
#include <alpha/pci/pcibus.h>
|
|
#include <alpha/isa/isavar.h>
|
|
|
|
char chipset_type[10];
|
|
int chipset_bwx = 0;
|
|
long chipset_ports = 0;
|
|
long chipset_memory = 0;
|
|
long chipset_dense = 0;
|
|
long chipset_hae_mask = 0;
|
|
|
|
SYSCTL_NODE(_hw, OID_AUTO, chipset, CTLFLAG_RW, 0, "PCI chipset information");
|
|
SYSCTL_STRING(_hw_chipset, OID_AUTO, type, CTLFLAG_RD, chipset_type, 0,
|
|
"PCI chipset type");
|
|
SYSCTL_INT(_hw_chipset, OID_AUTO, bwx, CTLFLAG_RD, &chipset_bwx, 0,
|
|
"PCI chipset supports BWX access");
|
|
SYSCTL_LONG(_hw_chipset, OID_AUTO, ports, CTLFLAG_RD, &chipset_ports,
|
|
"PCI chipset port address");
|
|
SYSCTL_LONG(_hw_chipset, OID_AUTO, memory, CTLFLAG_RD, &chipset_memory,
|
|
"PCI chipset memory address");
|
|
SYSCTL_LONG(_hw_chipset, OID_AUTO, dense, CTLFLAG_RD, &chipset_dense,
|
|
"PCI chipset dense memory address");
|
|
SYSCTL_LONG(_hw_chipset, OID_AUTO, hae_mask, CTLFLAG_RD, &chipset_hae_mask,
|
|
"PCI chipset mask for HAE register");
|
|
|
|
#ifdef notyet
|
|
|
|
/* return max number of devices on the bus */
|
|
int
|
|
pci_maxdevs(pcicfgregs *cfg)
|
|
{
|
|
return chipset.maxdevs(cfg->bus);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* read configuration space register */
|
|
|
|
int
|
|
pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
|
|
{
|
|
switch (bytes) {
|
|
case 1:
|
|
return chipset.cfgreadb(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg);
|
|
case 2:
|
|
return chipset.cfgreadw(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg);
|
|
case 4:
|
|
return chipset.cfgreadl(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg);
|
|
}
|
|
return ~0;
|
|
}
|
|
|
|
|
|
/* write configuration space register */
|
|
|
|
void
|
|
pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
|
|
{
|
|
switch (bytes) {
|
|
case 1:
|
|
return chipset.cfgwriteb(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg, data);
|
|
case 2:
|
|
return chipset.cfgwritew(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg, data);
|
|
case 4:
|
|
return chipset.cfgwritel(cfg->hose, cfg->bus,
|
|
cfg->slot, cfg->func, reg, data);
|
|
}
|
|
}
|
|
|
|
vm_offset_t
|
|
pci_cvt_to_dense(vm_offset_t sparse)
|
|
{
|
|
if(chipset.cvt_to_dense)
|
|
return ALPHA_PHYS_TO_K0SEG(chipset.cvt_to_dense(sparse));
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
vm_offset_t
|
|
pci_cvt_to_bwx(vm_offset_t sparse)
|
|
{
|
|
if(chipset.cvt_to_bwx)
|
|
return ALPHA_PHYS_TO_K0SEG(chipset.cvt_to_bwx(sparse));
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
alpha_platform_assign_pciintr(pcicfgregs *cfg)
|
|
{
|
|
if(platform.pci_intr_map)
|
|
platform.pci_intr_map((void *)cfg);
|
|
}
|
|
|
|
struct resource *
|
|
alpha_platform_alloc_ide_intr(int chan)
|
|
{
|
|
int irqs[2] = { 14, 15 };
|
|
return isa_alloc_intr(0, 0, irqs[chan]);
|
|
}
|
|
|
|
int
|
|
alpha_platform_release_ide_intr(int chan, struct resource *res)
|
|
{
|
|
return isa_release_intr(0, 0, res);
|
|
}
|
|
|
|
int
|
|
alpha_platform_setup_ide_intr(struct resource *res,
|
|
driver_intr_t *fn, void *arg,
|
|
void **cookiep)
|
|
{
|
|
return isa_setup_intr(0, 0, res, INTR_TYPE_BIO, fn, arg, cookiep);
|
|
}
|
|
|
|
int
|
|
alpha_platform_teardown_ide_intr(struct resource *res, void *cookie)
|
|
{
|
|
return isa_teardown_intr(0, 0, res, cookie);
|
|
}
|
|
|
|
static struct rman irq_rman, port_rman, mem_rman;
|
|
|
|
void pci_init_resources()
|
|
{
|
|
irq_rman.rm_start = 0;
|
|
irq_rman.rm_end = 64;
|
|
irq_rman.rm_type = RMAN_ARRAY;
|
|
irq_rman.rm_descr = "PCI Interrupt request lines";
|
|
if (rman_init(&irq_rman)
|
|
|| rman_manage_region(&irq_rman, 0, 63))
|
|
panic("pci_init_resources irq_rman");
|
|
|
|
port_rman.rm_start = 0;
|
|
port_rman.rm_end = ~0u;
|
|
port_rman.rm_type = RMAN_ARRAY;
|
|
port_rman.rm_descr = "I/O ports";
|
|
if (rman_init(&port_rman)
|
|
|| rman_manage_region(&port_rman, 0x0, (1L << 32)))
|
|
panic("pci_init_resources port_rman");
|
|
|
|
mem_rman.rm_start = 0;
|
|
mem_rman.rm_end = ~0u;
|
|
mem_rman.rm_type = RMAN_ARRAY;
|
|
mem_rman.rm_descr = "I/O memory";
|
|
if (rman_init(&mem_rman)
|
|
|| rman_manage_region(&mem_rman, 0x0, (1L << 32)))
|
|
panic("pci_init_resources mem_rman");
|
|
}
|
|
|
|
/*
|
|
* Allocate a resource on behalf of child. NB: child is usually going to be a
|
|
* child of one of our descendants, not a direct child of the pci chipset.
|
|
*/
|
|
struct resource *
|
|
pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
|
u_long start, u_long end, u_long count, u_int flags)
|
|
{
|
|
struct rman *rm;
|
|
struct resource *rv;
|
|
|
|
switch (type) {
|
|
case SYS_RES_IRQ:
|
|
rm = &irq_rman;
|
|
break;
|
|
|
|
case SYS_RES_IOPORT:
|
|
rm = &port_rman;
|
|
break;
|
|
|
|
case SYS_RES_MEMORY:
|
|
rm = &mem_rman;
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
rv = rman_reserve_resource(rm, start, end, count, flags, child);
|
|
if (rv == 0)
|
|
return 0;
|
|
|
|
switch (type) {
|
|
case SYS_RES_MEMORY:
|
|
rman_set_bustag(rv, ALPHA_BUS_SPACE_MEM);
|
|
rman_set_bushandle(rv, rv->r_start);
|
|
if (flags & PCI_RF_DENSE)
|
|
rman_set_virtual(rv, pci_cvt_to_dense(rv->r_start));
|
|
else if (flags & PCI_RF_BWX)
|
|
rman_set_virtual(rv, pci_cvt_to_bwx(rv->r_start));
|
|
else
|
|
rman_set_virtual(rv, (void *) rv->r_start); /* maybe NULL? */
|
|
break;
|
|
|
|
case SYS_RES_IOPORT:
|
|
rman_set_bustag(rv, ALPHA_BUS_SPACE_IO);
|
|
rman_set_bushandle(rv, rv->r_start);
|
|
break;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
int
|
|
pci_activate_resource(device_t bus, device_t child, int type, int rid,
|
|
struct resource *r)
|
|
{
|
|
return (rman_activate_resource(r));
|
|
}
|
|
|
|
int
|
|
pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
|
struct resource *r)
|
|
{
|
|
return (rman_deactivate_resource(r));
|
|
}
|
|
|
|
int
|
|
pci_release_resource(device_t bus, device_t child, int type, int rid,
|
|
struct resource *r)
|
|
{
|
|
return (rman_release_resource(r));
|
|
}
|
|
|
|
void
|
|
memcpy_fromio(void *d, u_int32_t s, size_t size)
|
|
{
|
|
char *cp = d;
|
|
|
|
while (size--)
|
|
*cp++ = readb(s++);
|
|
}
|
|
|
|
void
|
|
memcpy_toio(u_int32_t d, void *s, size_t size)
|
|
{
|
|
char *cp = s;
|
|
|
|
while (size--)
|
|
writeb(d++, *cp++);
|
|
}
|
|
|
|
void
|
|
memcpy_io(u_int32_t d, u_int32_t s, size_t size)
|
|
{
|
|
while (size--)
|
|
writeb(d++, readb(s++));
|
|
}
|
|
|
|
void
|
|
memset_io(u_int32_t d, int val, size_t size)
|
|
{
|
|
while (size--)
|
|
writeb(d++, val);
|
|
}
|
|
|
|
void
|
|
memsetw(void *d, int val, size_t size)
|
|
{
|
|
u_int16_t *sp = d;
|
|
|
|
while (size--)
|
|
*sp++ = val;
|
|
}
|
|
|
|
void
|
|
memsetw_io(u_int32_t d, int val, size_t size)
|
|
{
|
|
while (size--) {
|
|
writew(d, val);
|
|
d += sizeof(u_int16_t);
|
|
}
|
|
}
|
|
|
|
#include "opt_ddb.h"
|
|
#ifdef DDB
|
|
#include <ddb/ddb.h>
|
|
|
|
DB_COMMAND(in, db_in)
|
|
{
|
|
int c;
|
|
int size;
|
|
|
|
if (!have_addr)
|
|
return;
|
|
|
|
size = -1;
|
|
while ((c = *modif++) != '\0') {
|
|
switch (c) {
|
|
case 'b':
|
|
size = 1;
|
|
break;
|
|
case 'w':
|
|
size = 2;
|
|
break;
|
|
case 'l':
|
|
size = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (size < 0) {
|
|
db_printf("bad size\n");
|
|
return;
|
|
}
|
|
|
|
if (count <= 0) count = 1;
|
|
while (--count >= 0) {
|
|
db_printf("%08lx:\t", addr);
|
|
switch (size) {
|
|
case 1:
|
|
db_printf("%02x\n", inb(addr));
|
|
break;
|
|
case 2:
|
|
db_printf("%04x\n", inw(addr));
|
|
break;
|
|
case 4:
|
|
db_printf("%08x\n", inl(addr));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|