cardbus_cfg.c revision 11c2b4c0e543fe2e1e5910cde1f4422cc3218160
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) * Copyright (c) 2001 Tadpole Technology plc
* All rights reserved.
* From "@(#)pcicfg.c 1.31 99/06/18 SMI"
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Cardbus configurator
*/
#include <sys/ndi_impldefs.h>
#include <sys/sservice.h>
#include <sys/isa_defs.h>
#include <sys/ethernet.h>
#include "cardbus.h"
#include "cardbus_parse.h"
#include "cardbus_cfg.h"
/*
* ************************************************************************
* *** Implementation specific local data structures/definitions. ***
* ************************************************************************
*/
#define PCICFG_MAX_DEVICE 32
#define PCICFG_MAX_FUNCTION 8
#define PCICFG_NODEVICE 42
#define PCICFG_NOMEMORY 43
#define PCICFG_NOMULTI 44
#define PCICFG_MEMGRAN 0x100000
#define PCICFG_IOGRAN 0x1000
#define PCICFG_4GIG_LIMIT 0xFFFFFFFFUL
#define CBCFG_MEMGRAN 0x1000
#define CBCFG_IOGRAN 0x4
#define PCICFG_MEM_MULT 4
#define PCICFG_IO_MULT 4
/*
* ISA node declaration structure.
*/
struct isa_node {
char *name;
char *compatible[5];
char *type;
char *model;
};
struct cardbus_name_entry {
char *name;
int pil;
};
struct cardbus_find_ctrl {
};
(\
((ulong_t)(register & 0x3f)))
typedef struct cardbus_phdl cardbus_phdl_t;
struct cardbus_phdl {
int error;
};
typedef struct {
int io_decode_reg;
} isa_phdl_t;
/*
* forward declarations for routines defined in this module (called here)
*/
static int cardbus_program_ap(dev_info_t *);
static int cardbus_bridge_assign(dev_info_t *, void *);
static int cardbus_add_isa_reg(dev_info_t *, void *);
static int cardbus_free_chunk(dev_info_t *);
uint64_t *);
uint32_t *);
static int cardbus_sum_resources(dev_info_t *, void *);
static int cardbus_free_bridge_resources(dev_info_t *);
static int cardbus_free_device_resources(dev_info_t *);
static int cardbus_free_resources(dev_info_t *);
static void cardbus_config_teardown(ddi_acc_handle_t *);
static int cardbus_set_busnode_props(dev_info_t *);
static int cardbus_set_busnode_isaprops(dev_info_t *);
char *pval);
static void split_addr(char *, int *, int *);
#ifdef DEBUG
int nelems);
#endif
static struct cardbus_name_entry cardbus_class_lookup [] = {
{ 0x001, "display", 9 },
{ 0x100, "scsi", 4 },
{ 0x101, "ide", 4 },
{ 0x102, "fdc", 4 },
{ 0x103, "ipi", 4 },
{ 0x104, "raid", 4 },
{ 0x200, "ethernet", 6 },
{ 0x201, "token-ring", 6 },
{ 0x202, "fddi", 6 },
{ 0x203, "atm", 6 },
{ 0x300, "display", 9 }, /* VGA card */
{ 0x380, "display", 9 }, /* other - for the Raptor Card */
{ 0x400, "video", 11 },
{ 0x401, "sound", 11 },
{ 0x500, "memory", 11 },
{ 0x501, "flash", 11 },
{ 0x600, "host", 11 },
{ 0x601, "isa", 11 },
{ 0x602, "eisa", 11 },
{ 0x603, "mca", 11 },
{ 0x604, "pci", 11 },
{ 0x605, "pcmcia", 11 },
{ 0x606, "nubus", 11 },
{ 0x607, "cardbus", 11 },
{ 0x700, "serial", 11 },
{ 0x701, "parallel", 6 },
{ 0x800, "interrupt-controller", 3 },
{ 0x801, "dma-controller", 3 },
{ 0x802, "timer", 3 },
{ 0x803, "rtc", 3 },
{ 0x900, "keyboard", 8 },
{ 0x901, "pen", 8 },
{ 0x902, "mouse", 8 },
{ 0xa00, "dock", 1 },
{ 0xb00, "cpu", 1 },
{ 0xc00, "firewire", 9 },
{ 0xc01, "access-bus", 4 },
{ 0xc02, "ssa", 4 },
{ 0xc03, "usb", 9 },
{ 0xc04, "fibre-channel", 6 },
{ 0, 0 }
};
#ifndef _DONT_USE_1275_GENERIC_NAMES
#endif /* _DONT_USE_1275_GENERIC_NAMES */
/*
* Reprogram ILINE with default value only if BIOS doesn't program it
*/
int
{
"interrupt-line", 0xff);
DDI_PROP_CANSLEEP /* |DDI_PROP_DONTPASS */,
"interrupt-line", 0xb);
}
}
"interrupt-line", intline);
}
return (intline);
}
/*
* This entry point is called to configure a device (and
* all its children) on the given bus. It is called when
* a new device is added to the PCI domain. This routine
* will create the device tree and program the devices
* registers.
*/
int
{
int cardbus_dev, func;
&attach_point) != NDI_SUCCESS) {
"cardbus_configure(): Failed to alloc probe node\n");
return (PCICFG_FAILURE);
}
/*
* Node name marks this node as the "attachment point".
*/
"hp_attachment", 0) != NDI_SUCCESS) {
"Failed to set nodename for attachment node\n");
(void) ndi_devi_free(attach_point);
return (PCICFG_FAILURE);
}
"Set bus type to cardbus\n");
(void) ddi_prop_update_string(DDI_DEV_T_NONE,
"cardbus");
case PCICFG_FAILURE:
"configure failed: bus [0x%x] slot [0x%x] func [0x%x]\n",
goto cleanup;
case PCICFG_NODEVICE:
"no device: bus [0x%x] slot [0x%x] func [0x%x]\n",
goto cleanup;
default:
"configure: bus => [%d] slot => [%d] func => [%d]\n",
break;
}
(void) ndi_devi_free(attach_point);
return (PCICFG_SUCCESS);
}
/*
* Clean up a partially created "probe state" tree.
* There are no resources allocated to the in the
* probe state.
*/
"Look up device [0x%x] function [0x%x] to clean up\n",
cardbus_dev, func);
"Cleaning up device [0x%x] function [0x%x]\n",
cardbus_dev, func);
/*
* If this was a bridge device it will have a
* probe handle - if not, no harm in calling this.
*/
if (ddi_get_child(attach_point)) {
/*
* This will free up the node
*/
}
(void) ndi_devi_free(attach_point);
return (PCICFG_FAILURE);
}
int
{
(void) pci_config_teardown(&config_handle);
} else {
"cardbus_unconfigure(): Failed to setup config space\n");
}
(void) cardbus_free_chunk(dip);
"cardbus_unconfigure: calling cardbus_free_bridge_resources\n");
(void) cardbus_free_bridge_resources(dip);
return (PCICFG_SUCCESS);
}
int
{
/*
* Free up resources associated with 'dip'
*/
"cardbus_teardown_device: Failed to free resources\n");
return (PCICFG_FAILURE);
}
"cardbus_teardown_device: "
"Failed to offline and remove node\n");
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
/*
* Get the primary pci bus number. This should be the lowest number
* in the bus-range property of our parent.
*/
int
{
"device_type",
"cardbus_primary_busno: bus range is %d to %d\n",
return (rval);
}
}
"cardbus_primary_busno: Not a pci device or no bus-range\n");
return (-1);
}
static cardbus_phdl_t *
{
return (entry);
}
}
/*
* Did'nt find entry - create one
*/
return (cardbus_create_phdl(dip));
}
static cardbus_phdl_t *
{
return (new);
}
static int
{
if (entry == cardbus_phdl_list) {
} else {
}
/*
* If this entry has any allocated memory
* or IO space associated with it, that
* must be freed up.
*/
if (entry->memory_len > 0) {
#ifdef _LP64
"cardbus_destroy_phdl: "
"MEMORY BASE = [0x%lx] length [0x%lx]\n",
#else
"cardbus_destroy_phdl: "
"MEMORY BASE = [0x%llx] length [0x%llx]\n",
#endif
}
"cardbus_destroy_phdl: "
"IO BASE = [0x%x] length [0x%x]\n",
}
/*
* Destroy this entry
*/
return (PCICFG_SUCCESS);
}
}
/*
* Didn't find the entry
*/
return (PCICFG_FAILURE);
}
static int
{
"cardbus_program_ap: Failed to map config space!\n");
return (PCICFG_FAILURE);
}
"cardbus_program_ap (header_type=0x%x)\n", header_type);
(void) pci_config_teardown(&handle);
/*
* Header type two is PCI to Cardbus bridge, see page 43 of the
* CL-PD6832 data sheet
*/
switch (header_type & PCI_HEADER_TYPE_M) {
case PCI_HEADER_CARDBUS:
"cardbus_program_ap calling cardbus_allocate_chunk\n");
sec_bus) != PCICFG_SUCCESS) {
"cardbus_program_ap: "
"Not enough memory to hotplug\n");
(void) cardbus_destroy_phdl(dip);
return (PCICFG_FAILURE);
}
"cardbus_program_ap calling cardbus_find_phdl\n");
return (PCICFG_FAILURE);
}
"cardbus_program_ap calling cardbus_topbridge_assign\n");
(void) cardbus_destroy_phdl(dip);
}
break;
default:
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
static void
{
"cardbus_topbridge_bridge_assign: "
"Failed to map config space!\n");
return;
}
/* cardbus bridge is the same as PCI-PCI bridge */
(header_type == PCI_HEADER_CARDBUS));
(void) pci_config_teardown(&handle);
}
static int
{
int bus_range[2];
int count;
int i;
"Set up bus-range property to %u->%u\n",
"bus-range",
if (i == DDI_PROP_NOT_FOUND) {
"Create bus-range property, %u->%u\n",
sizeof (bus_range));
}
if (i != DDI_PROP_SUCCESS) {
"Failed to set bus-range property, %u->%u (%d)\n",
return (DDI_WALK_TERMINATE);
}
}
return (DDI_WALK_TERMINATE);
}
}
if (entry->memory_len > 0) {
"Failed to update ranges (memory)\n");
return (DDI_WALK_TERMINATE);
}
}
return (DDI_WALK_PRUNECHILD);
}
static int
{
int length;
int rcount;
int i;
int offset;
/*
* Ignore the attachment point and pcs.
*/
return (DDI_WALK_CONTINUE);
}
return (DDI_WALK_TERMINATE);
}
"cardbus_bridge_assign: Failed to map config space!\n");
return (DDI_WALK_TERMINATE);
}
/*
* This function is not called for the top bridge and we are
* not enumerating down a further cardbus interface yet!
*/
if (base_class == PCI_CLASS_BRIDGE) {
switch (sub_class) {
case PCI_BRIDGE_PCI:
if (header_type == PCI_HEADER_PPB) {
(void) cardbus_config_teardown(&handle);
return (i);
}
goto bad_device;
case PCI_BRIDGE_ISA:
(void) cardbus_config_teardown(&handle);
return (i);
case PCI_BRIDGE_CARDBUS:
/*
* Fall through, there should be at least one register
* set for this.
*/
break;
case PCI_BRIDGE_OTHER:
default:
break;
}
}
#ifdef sparc
/*
* If there is an interrupt pin set program
* interrupt line with default values.
*/
}
#else
#endif
/*
* A single device (under a bridge).
* For each "reg" property with a length, allocate memory
* and program the base registers.
*/
&length) != DDI_PROP_SUCCESS) {
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_TERMINATE);
}
for (i = 0; i < rcount; i++) {
case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
"REGISTER (64)LO [0x%x] ----> [0x%02x]\n",
"REGISTER (64)HI [0x%x] ----> [0x%02x]\n",
offset+4);
break;
case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
/* allocate memory space from the allocator */
reg[i].pci_phys_mid = 0;
if (((PCI_BASE_TYPE_M & request) ==
((PCI_BASE_SPACE_M & request) ==
"REGISTER (64)LO [0x%x] ----> "
"[0x%02x]\n",
offset);
offset + 4, 0);
"REGISTER (64)HI [0x%x] ----> "
"[0x%02x]\n",
offset+4);
} else {
"REGISTER (32)LO [0x%x] ----> "
"[0x%02x]\n",
offset);
}
break;
case PCI_REG_ADDR_G(PCI_ADDR_IO):
/* allocate I/O space from the allocator */
"REGISTER (I/O)LO [0x%x] ----> [0x%02x]\n",
break;
default:
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_TERMINATE);
} /* switch */
/*
* Now that memory locations are assigned,
* update the assigned address property.
*/
®[i]) != PCICFG_SUCCESS) {
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_TERMINATE);
}
}
}
#ifdef CARDBUS_DEBUG
if (cardbus_debug >= 9) {
}
#endif
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_CONTINUE);
}
static int
{
struct ebus_pci_rangespec range;
int count;
int length;
int rcount;
int i;
#ifdef sparc
/*
* If there is an interrupt pin set program
* interrupt line with default values.
*/
}
#else
#endif
/*
* For each "reg" property with a length, allocate memory.
*/
&length) != DDI_PROP_SUCCESS) {
return (DDI_WALK_TERMINATE);
}
for (i = 0; i < rcount; i++) {
case PCI_REG_ADDR_G(PCI_ADDR_IO):
/* allocate I/O space from the allocator */
"ISA (I/O)LO ----> [0x%x]\n", io_answer);
i = rcount;
break;
default:
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_TERMINATE);
} /* switch */
}
}
sizeof (range)/sizeof (int));
if (io_answer != 0xffffffff) {
/* i_ndi_block_device_tree_changes(&count); */
cardbus_add_isa_reg, (void *)&isa_phdl);
/* i_ndi_allow_device_tree_changes(count); */
}
return (DDI_WALK_PRUNECHILD);
}
/*
* This is specific to ITE8888 chip.
*/
static int
{
int length;
&length) != DDI_PROP_SUCCESS) {
return (DDI_WALK_CONTINUE);
}
return (DDI_WALK_CONTINUE);
}
/*
* Add the "reg" property.
*/
reg[0] = 0;
/*
* Generate the postive IO decode register setting.
*/
| (1uL <<31) /* Enable */
| (2uL <<29) /* Medium speed */
| (1uL <<28) /* Aliase enable, */
/* Don't care A[15:10] */
break;
}
if (io_reg) {
"cardbus_add_isa_reg: I/O decode reg (0x%x) set to 0x%x\n",
} else
"cardbus_add_isa_reg: register size (0x%x) too large\n",
breg[2]);
return (DDI_WALK_CONTINUE);
}
/*
* In case we want to ensure that some space is allocated to the
* device tree below the cardbus bridge.
* This is only necessary if there is a device that needs to allocate
* bridge downstream.
*/
static uint32_t cardbus_min_spare_mem = 0;
static uint32_t cardbus_min_spare_io = 0;
/*
* The "dip" passed to this routine is assumed to be
* the device at the attachment point. Currently it is
* assumed to be a bridge.
*/
static int
{
int count;
/*
* This should not find an existing entry - so
* it will create a new one.
*/
/*
* Set highest_bus here.
* Otherwise if we don't find another bridge
* this never gets set.
*/
/*
* From this point in the tree - walk the devices,
* The function passed in will read and "sum" up
* the memory and I/O requirements and put them in
* structure "phdl".
*/
}
/*
* Call into the memory allocator with the request.
* Record the addresses returned in the phdl
*/
#ifdef _LP64
"AP requires [0x%lx] bytes of memory space, alligned 0x%x\n",
"AP requires [0x%lx] bytes of I/O space, alligned 0x%x\n",
#else
"AP requires [0x%llx] bytes of memory space, alligned 0x%x\n",
"AP requires [0x%llx] bytes of I/O space, alligned 0x%x\n",
#endif
if (mem_request->ra_len) {
phdl->memory_gran);
#ifdef _LP64
"cardbus_allocate_chunk: ndi_ra_alloc 0x%lx bytes\n",
#else
"cardbus_allocate_chunk: ndi_ra_alloc 0x%llx bytes\n",
#endif
return (PCICFG_FAILURE);
}
}
if (io_request->ra_len) {
#else
io_request->ra_boundbase = 0;
#endif
if (mem_request->ra_len) {
}
return (PCICFG_FAILURE);
}
}
#ifdef _LP64
"MEMORY BASE = [0x%lx] length [0x%lx]\n",
#else
"MEMORY BASE = [0x%llx] length [0x%llx]\n",
#endif
"IO BASE = [0x%x] length [0x%x]\n",
return (PCICFG_SUCCESS);
}
static int
{
int k;
(void) cardbus_destroy_phdl(dip);
&k) != DDI_PROP_SUCCESS) {
"cardbus_free_chunk: Failed to read bus-range property\n");
return (PCICFG_FAILURE);
}
"cardbus_free_chunk: Freeing bus [%d] range [%d]\n",
if (ndi_ra_free(dip,
"cardbus_free_chunk: Failed to free bus numbers\n");
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
/*
* Put bridge registers into initial state
*/
static void
{
#ifdef _LP64
"cardbus_setup_bridge: "
"highest bus %d, mem_last 0x%lx, io_last 0x%x\n",
#else
"cardbus_setup_bridge: "
"highest bus %d, mem_last 0x%llx, io_last 0x%x\n",
#endif
/*
* The highest bus seen during probing is
* the max-subordinate bus
*/
#ifdef _LP64
"Adding [0x%lx] before bridge (mem)\n",
#else
"Adding [0x%llx] before bridge (mem)\n",
#endif
}
/*
* Program the memory base register with the
* start of the memory range
*/
#ifdef _LP64
"store 0x%x(0x%lx) in pci bridge memory base register\n",
entry->memory_last);
#else
"store 0x%x(0x%llx) in pci bridge memory base register\n",
entry->memory_last);
#endif
"Adding [0x%x] before bridge (I/O)\n",
}
"store 0x%02x/0x%04x(0x%x) in "
/*
* Program the I/O base register with the start of the I/O range
*/
/*
* Clear status bits
*/
/*
* Turn off prefetchable range
*/
#ifdef sparc
/*
* If there is an interrupt pin set program
* interrupt line with default values.
*/
}
#else
#endif
/*
* The highest bus seen during probing is
* the max-subordinate bus
*/
entry->highest_bus);
/*
* Program the memory base register with the
* start of the memory range
*/
#ifdef _LP64
"store 0x%x(0x%lx) in "
"cardbus memory base register 0, len 0x%lx\n",
entry->memory_len);
#else
"store 0x%x(0x%llx) in "
"cardbus memory base register 0, len 0x%llx\n",
entry->memory_len);
#endif
/*
* Program the I/O base register with the start of the I/O range
*/
"store 0x%x in cb IO base register 0 len 0x%x\n",
/*
* Clear status bits
*/
#ifdef sparc
/*
* If there is an interrupt pin set program
* interrupt line with default values.
*/
}
#else
#endif
/*
* LATER: use these registers
*/
} else {
}
}
static void
{
if (header_type == PCI_HEADER_CARDBUS)
else
/*
* Program the memory limit register with the end of the memory range
*/
#ifdef _LP64
"cardbus_update_bridge: Mem base 0x%lx len 0x%lx "
"last 0x%lx gran 0x%x gran end 0x%lx\n",
#else
"cardbus_update_bridge: Mem base 0x%llx len 0x%llx "
"last 0x%llx gran 0x%x gran end 0x%lx\n",
#endif
/*
* Since this is a bridge, the rest of this range will
* be responded to by the bridge. We have to round up
* so no other device claims it.
*/
if (length > 0) {
/*
* This is to allow space that isn't actually being used by
* anything to be allocated by devices such as a downstream
* PCMCIA controller.
*/
"Added [0x%x] at the top of the bridge (mem)\n", length);
}
if (entry->memory_len) {
if (header_type == PCI_HEADER_CARDBUS) {
#ifdef _LP64
"store 0x%x(0x%lx) in memory limit register 0\n",
#else
"store 0x%x(0x%llx) in memory limit register 0\n",
#endif
} else {
#ifdef _LP64
"store 0x%x(0x%lx) in memory limit register\n",
rlval);
#else
"store 0x%x(0x%llx) in memory limit register\n",
rlval);
#endif
}
word16 |= PCI_COMM_MAE;
}
"cardbus_update_bridge: I/O base 0x%x len 0x%x last 0x%x "
"gran 0x%x gran_end 0x%lx\n",
if (header_type == PCI_HEADER_CARDBUS)
else
/*
* Same as above for I/O space. Since this is a
* bridge, the rest of this range will be responded
* to by the bridge. We have to round up so no
* other device claims it.
*/
if (length > 0) {
"Added [0x%x] at the top of the bridge (I/O)\n", length);
}
/*
* Program the I/O limit register with the end of the I/O range
*/
if (header_type == PCI_HEADER_CARDBUS) {
#ifdef _LP64
"store 0x%lx in IO limit register 0\n", rlval);
#else
"store 0x%llx in IO limit register 0\n", rlval);
#endif
} else {
#ifdef _LP64
"store 0x%x/0x%x(0x%lx) in "
rlval);
#else
"store 0x%x/0x%x(0x%llx) in "
rlval);
#endif
}
word16 |= PCI_COMM_IO;
}
}
static void
{
#ifdef _LP64
"cardbus_get_mem: memory_last 0x%lx, length 0x%x, "
"memory_base 0x%lx, memory_len 0x%lx ans=0x%p\n",
#else
"cardbus_get_mem: memory_last 0x%llx, length 0x%x, "
"memory_base 0x%llx, memory_len 0x%llx ans=0x%p\n",
#endif
if (ans) {
/*
* Round up the request to the "size" boundary
*/
- entry->memory_last;
if (hole != 0) {
(void) cardbus_update_available_prop(dip,
#ifdef _LP64
"cardbus_get_mem: "
"rounded memory_last up by 0x%x to 0x%lx, ",
#else
"cardbus_get_mem: "
"rounded memory_last up by 0x%x to 0x%llx, ",
#endif
}
} else
/*
* These routines should parcel out the memory
* completely. There should never be a case of
* over running the bounds.
*/
#ifdef _LP64
"cardbus_get_mem: assert will fail %ld <= %ld,"
"(0x%lx + 0x%x) <= (0x%lx + 0x%lx)\n",
#else
"cardbus_get_mem: assert will fail %lld <= %lld, "
"(0x%llx + 0x%x) <= (0x%llx + 0x%llx)\n",
#endif
entry->memory_len);
/*
* If ans is NULL don't return anything,
* they are just asking to reserve the memory.
*/
/*
* Increment to the next location
*/
}
static void
{
"cardbus_get_io: io_last 0x%x, length 0x%x, "
"io_base 0x%x, io_len 0x%x ans=0x%p\n",
if (ans) {
/*
* Round up the request to the "size" boundary
*/
if (hole != 0) {
"cardbus_get_io: "
"rounded io_last up by 0x%x to 0x%x, ",
}
} else
/*
* These routines should parcel out the memory
* completely. There should never be a case of
* over running the bounds.
*/
/*
* If ans is NULL don't return anything,
* they are just asking to reserve the memory.
*/
/*
* Increment to the next location
*/
}
static int
{
int length;
int rcount;
int i, ret;
/*
* Ignore the attachment point and pcs.
*/
return (DDI_WALK_CONTINUE);
}
"cardbus_sum_resources: Failed to map config space!\n");
return (DDI_WALK_TERMINATE);
}
/*
* If its a bridge - just record the highest bus seen
*/
if (base_class == PCI_CLASS_BRIDGE) {
switch (sub_class) {
case PCI_BRIDGE_PCI:
if ((header_type & PCI_HEADER_TYPE_M)
== PCI_HEADER_PPB) {
PCI_BCNF_SECBUS)) {
}
(void) cardbus_config_teardown(&handle);
#if defined(CARDBUS_DEBUG)
if (mem_request->ra_len !=
PCICFG_MEMGRAN)) {
#ifdef _LP64
"Pre-align [0x%lx] to PCI bridge "
"memory gran "
"[0x%lx] -> [0x%lx]\n",
#else
"Pre-align [0x%llx] to PCI bridge "
"memory gran "
"[0x%llx] -> [0x%lx]\n",
#endif
}
if (io_request->ra_len !=
PCICFG_IOGRAN)) {
#ifdef _LP64
"Pre-align [0x%lx] to PCI bridge "
"I/O gran "
"[0x%lx] -> [0x%lx]\n",
#else
"Pre-align [0x%llx] to PCI bridge "
"I/O gran "
"[0x%llx] -> [0x%lx]\n",
#endif
}
#endif
(void *)entry);
#if defined(CARDBUS_DEBUG)
if (mem_request->ra_len !=
#ifdef _LP64
"Post-align [0x%lx] to PCI bridge "
"memory gran "
"[0x%lx] -> [0x%lx]\n",
#else
"Post-align [0x%llx] to PCI bridge "
"memory gran "
"[0x%llx] -> [0x%lx]\n",
#endif
}
if (io_request->ra_len !=
PCICFG_IOGRAN)) {
#ifdef _LP64
"Post-align [0x%lx] to PCI bridge "
"I/O gran "
"[0x%lx] -> [0x%lx]\n",
#else
"Post-align [0x%llx] to PCI bridge "
"I/O gran "
"[0x%llx] -> [0x%lx]\n",
#endif
}
#endif
io_request->ra_len +
}
return (DDI_WALK_PRUNECHILD);
case PCI_BRIDGE_CARDBUS:
/*
* Cardbus has I/O registers.
*/
break;
case PCI_BRIDGE_ISA:
/*
* All the registers requirements for ISA
* are stored in the reg structure of the bridge.
* Children of ISA are not of type PCI
* so must not come through here because
* cardbus_config_setup() will fail.
*/
break;
default:
/*
* Treat other bridges as leaf nodes.
*/
break;
}
}
&length) != DDI_PROP_SUCCESS) {
/*
* If one node in (the subtree of nodes)
* does'nt have a "reg" property fail the
* allocation.
*/
entry->memory_len = 0;
(void) cardbus_config_teardown(&handle);
return (DDI_WALK_TERMINATE);
}
/*
* For each "reg" property with a length, add that to the
* total memory (or I/O) to allocate.
*/
for (i = 0; i < rcount; i++) {
case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
pci_rp[i].pci_size_low +
pci_rp[i].pci_size_low);
"ADDING 32 --->0x%x for BAR@0x%x\n",
pci_rp[i].pci_size_low,
/*
* the granualarity needs to be the larger of
* the maximum amount of memory that we're going to
* ask for, and the PCI-PCI bridge granularity (1M)
*/
break;
case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
pci_rp[i].pci_size_low +
pci_rp[i].pci_size_low);
"ADDING 64 --->0x%x for BAR@0x%x\n",
pci_rp[i].pci_size_low,
break;
case PCI_REG_ADDR_G(PCI_ADDR_IO):
io_request->ra_len =
pci_rp[i].pci_size_low +
pci_rp[i].pci_size_low);
"ADDING I/O --->0x%x for BAR@0x%x\n",
pci_rp[i].pci_size_low,
break;
default:
/* Config space register - not included */
break;
}
}
/*
* free the memory allocated by ddi_getlongprop
*/
/*
* continue the walk to the next sibling to sum memory
*/
(void) cardbus_config_teardown(&handle);
#ifdef _LP64
"Memory 0x%lx bytes, I/O 0x%lx bytes, "
"Memgran 0x%x, IOgran 0x%x\n",
#else
"Memory 0x%llx bytes, I/O 0x%llx bytes, "
"Memgran 0x%x, IOgran 0x%x\n",
#endif
return (ret);
}
/*
* Free resources allocated to a bridge.
* Note that this routine does not call ndi_ra_free() to actually
* device tree in cardbus_free_chunk().
*/
static int
{
int k;
int length;
int i;
&length) == DDI_PROP_SUCCESS) {
for (i = 0; i < length / sizeof (cardbus_range_t); i++) {
case PCI_ADDR_IO:
"Need to Free I/O "
break;
case PCI_ADDR_MEM32:
case PCI_ADDR_MEM64:
"[0x%x.%x]/[0x%x]\n",
break;
default:
"Unknown memory space\n");
break;
}
}
}
} else {
"cardbus_free_bridge_resources: Failed"
"to read ranges property\n");
}
&k) != DDI_PROP_SUCCESS) {
return (PCICFG_FAILURE);
}
"Need to free bus [%d] range [%d]\n",
return (PCICFG_SUCCESS);
}
static int
{
int length;
int acount;
int i;
DDI_PROP_DONTPASS, "assigned-addresses",
&length) != DDI_PROP_SUCCESS) {
"Failed to read assigned-addresses property\n");
return (PCICFG_FAILURE);
}
/*
* For each "assigned-addresses" property entry with a length,
* call the memory allocation routines to return the
* resource.
*/
for (i = 0; i < acount; i++) {
/*
* Free the resource if the size of it is not zero.
*/
if ((assigned[i].pci_size_low != 0)||
(assigned[i].pci_size_hi != 0)) {
case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
"Need to return 0x%x of 32 bit MEM space"
" @ 0x%x from register 0x%x\n",
assigned[i].pci_size_low,
assigned[i].pci_phys_low,
break;
case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
"Need to return 0x%x of 64 bit MEM space"
" @ 0x%x.%x from register 0x%x\n",
assigned[i].pci_size_low,
assigned[i].pci_phys_mid,
assigned[i].pci_phys_low,
break;
case PCI_REG_ADDR_G(PCI_ADDR_IO):
"Need to return 0x%x of IO space @ 0x%x"
" from register 0x%x\n",
assigned[i].pci_size_low,
assigned[i].pci_phys_low,
break;
default:
return (PCICFG_FAILURE);
} /* switch */
}
}
return (PCICFG_SUCCESS);
}
static int
{
"class-code", -1);
/*
* A different algorithim is used for bridges and leaf devices.
*/
if (classcode != -1) {
!= PCICFG_SUCCESS) {
"Failed freeing up bridge resources\n");
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
}
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
static int
{
/* Declairations */
int i, j;
int circ;
"cardbus_probe_bridge bus %d device %d func %d\n",
"cardbus_probe_bridge(): Failed to setup config space\n");
return (PCICFG_FAILURE);
}
/*
* As soon as we have access to config space, check device
* is a bridge.
*/
goto failed;
"---Vendor ID = [0x%04x]\n",
"---Device ID = [0x%04x]\n",
/* say what type of header */
"--%s bridge found root bus [0x%x] device [0x%x] func [0x%x]\n",
"PCI-PCI" : "Cardbus",
"No bus-range property seems to have been set up\n");
else {
"allowable bus range is %u->%u\n",
}
/*
* Get next bus in sequence and program device.
*/
NDI_RA_PASS) != NDI_SUCCESS) {
goto failed;
}
/* Enable it all */
/*
* Probe all children devices
*/
for (i = 0; i < pcicfg_max_device; i++)
for (j = 0; j < pcicfg_max_function; j++)
j, &header_type)) {
case PCICFG_FAILURE:
"Failed to configure bus "
"[0x%x] device [0x%x] func [0x%x]\n",
new_bus, i, j);
goto failed;
case PCICFG_NODEVICE:
/*
* if there's no function 0
* there's no point in probing other
* functions
*/
if (j != 0)
break;
/* FALLTHROUGH */
case PCICFG_NOMULTI:
j = pcicfg_max_function;
break;
default:
break;
}
(void) pci_config_teardown(&config_handle);
return (PCICFG_SUCCESS);
(void) pci_config_teardown(&config_handle);
return (PCICFG_FAILURE);
}
};
static int
{
int i, j;
int ret;
int circ;
"cardbus_probe_children bus %d device %d func %d\n",
/*
* This node will be put immediately below
* "parent". Allocate a blank device node. It will either
* be filled in or freed up based on further probing.
*/
&new_child) != NDI_SUCCESS) {
"cardbus_probe_children(): Failed to alloc child node\n");
return (PCICFG_FAILURE);
}
"cardbus_probe_children(): Failed to add candidate REG\n");
goto failedconfig;
}
!= PCICFG_SUCCESS) {
if (ret == PCICFG_NODEVICE) {
(void) ndi_devi_free(new_child);
return (ret);
}
"cardbus_probe_children(): Failed to setup config space\n");
goto failedconfig;
}
if (func == 0) {
/*
* Preserve the header type from function 0.
* Additional functions may not preserve the PCI_HEADER_MULTI
* bit.
*/
} else if (!(*header_type & PCI_HEADER_MULTI) ||
(base_class == PCI_CLASS_BRIDGE)) {
(void) cardbus_config_teardown(&config_handle);
(void) ndi_devi_free(new_child);
return (PCICFG_NOMULTI);
}
/*
* As soon as we have access to config space,
* turn off device. It will get turned on
* later (after memory is assigned).
* not if it's a cardbus device. It may be OK to leave
* it on - try LATER
*/
/*
* Set 1275 properties common to all devices
*/
config_handle) != PCICFG_SUCCESS) {
goto failedchild;
}
/*
* Child node properties NOTE: Both for PCI-PCI bridge and child node
*/
config_handle) != PCICFG_SUCCESS) {
goto failedchild;
}
"---Vendor ID = [0x%04x]\n",
"---Device ID = [0x%04x]\n",
if (base_class == PCI_CLASS_BRIDGE) {
switch (sub_class) {
case PCI_BRIDGE_PCI:
if ((*header_type & PCI_HEADER_TYPE_M)
== PCI_HEADER_PPB) {
int k;
/* say what type of header */
"-- Found PCI-PCI bridge @ "
" bus [0x%x] device [0x%x] func [0x%x]\n",
new_child, 0, "bus-range",
&k) != DDI_PROP_SUCCESS)
"No bus-range property"
" seems to have been set up\n");
else {
"allowable bus range is %u->%u\n",
}
/*
* Get next bus in sequence and program device.
*/
NDI_RA_PASS) != NDI_SUCCESS) {
"Failed to get a bus number\n");
goto failedchild;
}
/* Enable it all */
(void) cardbus_set_bus_numbers(config_handle,
#if defined(CARDBUS_DEBUG)
if (cardbus_debug >= 9) {
}
#endif
/*
* Set bus properties
*/
!= PCICFG_SUCCESS) {
"Failed to set busnode props\n");
goto failedchild;
}
/*
* Probe all children devices
*/
for (i = 0; i < pcicfg_max_device; i++)
for (j = 0; j < pcicfg_max_function;
j++)
switch (cardbus_probe_children(
cbp,
new_bus, i,
j, header_type)) {
case PCICFG_FAILURE:
"Failed to "
"configure "
"bus [0x%x] "
"device [0x%x] "
"func [0x%x]\n",
new_bus, i, j);
goto failedchild;
case PCICFG_NODEVICE:
/*
* if there's no
* function 0
* there's no point in
* probing other
* functions
*/
if (j != 0)
break;
/* FALLTHROUGH */
case PCICFG_NOMULTI:
j = pcicfg_max_function;
break;
default:
break;
}
}
break;
case PCI_BRIDGE_CARDBUS:
"--Found Cardbus bridge @ "
"bus [0x%x] device [0x%x] func [0x%x]\n",
PCI_CONF_BASE0, 0xffffffff);
/*
* If its a zero length, don't do
* any programming.
*/
if (request != 0) {
"cardbus_probe_children: "
"can't access device");
goto failedchild;
}
/*
* Add to the "reg" property
*/
PCI_CONF_BASE0) != PCICFG_SUCCESS) {
goto failedchild;
}
"BASE register [0x%x] asks for "
"[0x%x]=[0x%x](32)\n",
}
break;
case PCI_BRIDGE_ISA:
"--Found ISA bridge @ "
"bus [0x%x] device [0x%x] func [0x%x]\n",
#if defined(CARDBUS_DEBUG)
if (cardbus_debug >= 4) {
" DDMA SlvCh0 = [0x%04x] "
"DDMA SlvCh1 = [0x%04x]\n",
" DDMA SlvCh2 = [0x%04x] "
"DDMA SlvCh3 = [0x%04x]\n",
" DDMA SlvCh5 = [0x%04x] "
"DDMA SlvCh6 = [0x%04x]\n",
" DDMA SlvCh7 = [0x%04x] "
"Misc Cntrl = [0x%02x]\n",
" DMA Cntl = [0x%02x] "
"DMA TyF Tim = [0x%02x]\n",
" TimCntrl = [0x%02x] "
"MTOP = [0x%02x]\n",
" MDMA Access = [0x%02x] "
"ROMCS = [0x%02x]\n",
" Dscrd Tmr = [0x%02x] "
"Retry Tmr = [0x%02x]\n",
" I/O Spc 0 = [0x%08x] "
"I/O Spc 1 = [0x%08x]\n",
" I/O Spc 2 = [0x%08x] "
"I/O Spc 3 = [0x%08x]\n",
" I/O Spc 4 = [0x%08x] "
"I/O Spc 5 = [0x%08x]\n",
" Mem Spc 0 = [0x%08x] "
"Mem Spc 1 = [0x%08x]\n",
" Mem Spc 2 = [0x%08x] "
"Mem Spc 3 = [0x%08x]\n",
}
#endif
/*
* Set bus properties
*/
!= PCICFG_SUCCESS) {
"Failed to set busnode props\n");
goto failedchild;
}
/*
* Add to the "reg" property.
* Simply grab 1K of I/O space.
*/
0xfffffc00 | PCI_BASE_SPACE_IO,
PCI_CONF_BASE0) != PCICFG_SUCCESS) {
goto failedchild;
}
/*
* Probe all potential children devices.
*/
for (i = 0;
i++)
&isa_nodes[i])) {
case PCICFG_FAILURE:
"Failed to configure isa bus\n");
goto failedchild;
case PCICFG_NODEVICE:
continue;
}
break;
case PCI_BRIDGE_OTHER:
default:
"--Found unknown bridge, subclass 0x%x @ "
"bus [0x%x] device [0x%x] func [0x%x]\n",
goto leaf_node;
}
} else {
"--Leaf device found "
"bus [0x%x] device [0x%x] func [0x%x]\n",
/*
* Ethernet devices.
*/
extern int localetheraddr(struct ether_addr *,
struct ether_addr *);
"device_type", "network");
(void) ddi_prop_create(DDI_DEV_T_NONE,
DDI_PROP_CANSLEEP, "local-mac-address",
}
}
if (cdsp->binding_name &&
cdsp->binding_name))
continue;
continue;
continue;
0) != NDI_SUCCESS)
"Failed to set nodename\n");
}
switch (propp->prop_flags) {
case DDI_PROP_TYPE_INT:
break;
case DDI_PROP_TYPE_STRING:
break;
case DDI_PROP_TYPE_ANY:
break;
}
}
}
}
#if defined(CARDBUS_DEBUG)
if (cardbus_debug >= 9) {
}
#endif
i = PCI_CONF_BASE0;
while (i <= PCI_CONF_BASE5) {
/*
* If its a zero length, don't do
* any programming.
*/
if (request != 0) {
"cardbus_probe_children: "
"can't access device");
goto failedchild;
}
/*
* Add to the "reg" property
*/
request, i) != PCICFG_SUCCESS) {
goto failedchild;
}
} else {
break;
}
/*
* Increment by eight if it is 64 bit address space
* only if memory space
*/
if (((PCI_BASE_TYPE_M & request)
== PCI_BASE_TYPE_ALL) &&
((PCI_BASE_SPACE_M & request)
== PCI_BASE_SPACE_MEM)) {
"BASE register [0x%x] asks for "
"[0x%x]=[0x%x] (64)\n",
i, request,
i += 8;
} else {
"BASE register [0x%x] asks for "
"[0x%x]=[0x%x](32)\n",
i, request,
i += 4;
}
}
/*
* Get the ROM size and create register for it
*/
/*
* If its a zero length, don't do
* any programming.
*/
if (request != 0) {
"BASE register [0x%x] asks for "
"[0x%x]=[0x%x] (ROM)\n",
/*
* Add to the "reg" property
*/
PCI_CONF_ROM) != PCICFG_SUCCESS) {
goto failedchild;
}
}
}
(void) cardbus_config_teardown(&config_handle);
/*
* Attach the child to its parent
*/
return (PCICFG_SUCCESS);
/*
* check if it should be taken offline (if online)
*/
(void) cardbus_config_teardown(&config_handle);
(void) ndi_devi_free(new_child);
return (PCICFG_FAILURE);
}
static int
{
}
static int
{
int ret;
/*
* This node will be put immediately below
* "parent". Allocate a blank device node.
*/
&new_child) != NDI_SUCCESS) {
"cardbus_add_isa_child(): Failed to alloc child node\n");
return (PCICFG_FAILURE);
}
/*
* Set properties common to ISA devices
*/
goto failed;
}
/*
* Add the "reg" property.
*/
reg[0] = 0;
if (ret != DDI_SUCCESS)
goto failed;
return (PCICFG_SUCCESS);
(void) ndi_devi_free(new_child);
return (PCICFG_FAILURE);
}
static int
{
int status;
int rlen;
int ret;
#ifdef sparc
#endif
"cardbus_config_setup(dip=0x%p)\n", (void *) dip);
/*
* Get the pci register spec from the node
*/
"cardbus_config_setup, reg = 0x%p\n", (void *) reg);
switch (status) {
case DDI_PROP_SUCCESS:
break;
case DDI_PROP_NO_MEMORY:
return (PCICFG_FAILURE);
default:
return (PCICFG_FAILURE);
}
/*
* Find the attachment point node
*/
"hp_attachment") != 0)) {
}
return (PCICFG_FAILURE);
}
"Failed to update reg property, error code %d\n", ret);
return (PCICFG_FAILURE);
}
0, /* PCI_CONF_HDR_SIZE */
0,
"Failed to setup registers for [0x%x][0x%x][0x%x]\n",
return (PCICFG_FAILURE);
}
"PROBING =>->->->->->-> [0x%x][0x%x][0x%x] 0x%x 0x%p\n",
/*
* must do peek16 otherwise the system crashes when probing
* a non zero function on a non-multi-function card.
*/
#ifdef sparc
"cardbus_config_setup peek failed\n");
"cardbus_config_setup PCICFG_NODEVICE\n");
"cardbus_config_setup PCICFG_NODEVICE\n");
#endif
} else {
"cardbus_config_setup found device at:[0x%x][0x%x][0x%x]\n",
}
if (ret != PCICFG_SUCCESS) {
}
"cardbus_config_setup returning %d\n", ret);
return (ret);
}
static void
{
(void) ddi_regs_map_free(handle);
}
static void
{
int circ;
/*
* Unlink node from tree before reparenting
*/
}
}
static int
{
int alen;
switch (status) {
case DDI_PROP_SUCCESS:
"cardbus_update_assigned_prop: found prop len %d\n",
alen);
/*
* Allocate memory for the existing
* assigned-addresses(s) plus one and then
* build it.
*/
break;
case DDI_PROP_NO_MEMORY:
"no memory for assigned-addresses property\n");
return (PCICFG_FAILURE);
default:
"cardbus_update_assigned_prop: creating prop\n");
alen = 0;
break;
}
/*
* Write out the new "assigned-addresses" spec
*/
"assigned-addresses", (int *)newreg,
if (status == DDI_PROP_SUCCESS)
if (alen)
return (PCICFG_SUCCESS);
}
static int
{
switch (status) {
case DDI_PROP_SUCCESS:
break;
case DDI_PROP_NO_MEMORY:
return (PCICFG_FAILURE);
default:
return (PCICFG_FAILURE);
}
switch (status) {
case DDI_PROP_SUCCESS:
break;
case DDI_PROP_NO_MEMORY:
return (PCICFG_FAILURE);
default:
alen = 0;
}
/*
* Allocate memory for the existing
* available(s) plus one and then
* build it.
*/
/*
* Build the regspec, then add it to the existing one(s)
*/
#ifdef DEBUG
#endif
if (alen)
/*
* Write out the new "available" spec
*/
"available", (int *)newreg,
(alen + sizeof (pci_regspec_t))/sizeof (int));
if (alen)
return (PCICFG_SUCCESS);
}
static int
{
int rlen;
#if defined(CARDBUS_DEBUG)
int i, nrange;
const cardbus_range_t *nr;
#endif
switch (status) {
case DDI_PROP_SUCCESS:
break;
case DDI_PROP_NO_MEMORY:
"ranges present, but unable to get memory\n");
return (PCICFG_FAILURE);
default:
sizeof (cardbus_range_t)/sizeof (int))
!= DDI_SUCCESS) {
return (PCICFG_FAILURE);
}
return (PCICFG_SUCCESS);
}
/*
* Allocate memory for the existing reg(s) plus one and then
* build it.
*/
/*
* Write out the new "ranges" property
*/
(rlen + sizeof (cardbus_range_t))/sizeof (int));
#if defined(CARDBUS_DEBUG)
for (i = 0; i <= nrange; i++) {
/* nrange is one higher for new entry */
"\trange parent addr 0x%x.0x%x.0x%x "
"child addr 0x%x.0x%x.0x%x size 0x%x.0x%x\n",
nr++;
}
#endif
return (PCICFG_SUCCESS);
}
static int
{
int rlen;
switch (status) {
case DDI_PROP_SUCCESS:
break;
case DDI_PROP_NO_MEMORY:
return (PCICFG_FAILURE);
default:
return (PCICFG_FAILURE);
}
/*
* Allocate memory for the existing reg(s) plus one and then
* build it.
*/
/*
* Build the regspec, then add it to the existing one(s)
*/
if (reg_offset == PCI_CONF_ROM) {
hiword |= PCI_ADDR_MEM32;
} else {
hiword |= PCI_ADDR_MEM32;
} else if ((PCI_BASE_TYPE_M & regvalue)
== PCI_BASE_TYPE_ALL) {
/*
* This is a 64 bit PCI memory space.
* It needs to be allocated as 32 bit
* for bus map purposes.
*/
hiword |= PCI_ADDR_MEM32;
}
} else {
hiword |= PCI_ADDR_IO;
}
}
addition.pci_phys_mid = 0;
addition.pci_phys_low = 0;
addition.pci_size_hi = 0;
"cardbus_update_reg_prop, phys_hi 0x%08x,"
" phys_mid 0x%08x, phys_low 0x%08x, size_hi 0x%08x,"
/*
* Write out the new "reg" property
*/
(rlen + sizeof (pci_regspec_t))/sizeof (int));
return (PCICFG_SUCCESS);
}
/*
* Setup the basic 1275 properties based on information found in the config
* header of the PCI device
*/
static int
{
int ret;
/* These two exists only for non-bridges */
if ((pci_config_get8(config_handle,
return (ret);
}
return (ret);
}
}
/*
* These should always exist and have the value of the
* corresponding register value
*/
/*
* according to section 6.2.1 of revision 2 of the PCI local
* bus specification - 0FFFFh is an invalid value for the vendor ID
*/
if (val == 0xffff) {
return (PCICFG_FAILURE);
}
return (ret);
}
return (ret);
}
return (ret);
}
return (ret);
}
return (ret);
}
/*
* The next three are bits set in the status register. The property is
* present (but with no value other than its own existence) if the bit
* is set, non-existent otherwise
*/
"fast-back-to-back") &&
"fast-back-to-back", 0)) != DDI_SUCCESS) {
return (ret);
}
}
"66mhz-capable", 0)) != DDI_SUCCESS) {
return (ret);
}
}
"udf-supported", 0)) != DDI_SUCCESS) {
return (ret);
}
}
/*
* These next three are optional and are not present
* if the corresponding register is zero. If the value
* is non-zero then the property exists with the value
* of the register.
*/
/* look in the correct place for header type 2 */
PCI_CBUS_SUBVENID)) != 0) {
return (ret);
}
}
PCI_CBUS_SUBSYSID)) != 0) {
return (ret);
}
}
} else {
PCI_CONF_SUBVENID)) != 0) {
return (ret);
}
}
PCI_CONF_SUBSYSID)) != 0) {
return (ret);
}
}
}
PCI_CONF_CACHE_LINESZ)) != 0) {
return (ret);
}
}
/*
* If the Interrupt Pin register is non-zero then the
* interrupts property exists
*/
/*
* If interrupt pin is non-zero,
* record the interrupt line used
*/
return (ret);
}
}
return (PCICFG_SUCCESS);
}
/*
* Setup the basic properties required by the ISA node.
*/
static int
{
int ret, n;
return (ret);
}
/*
* The node name field needs to be filled in with the name
*/
return (PCICFG_FAILURE);
}
/*
* Create the compatible property as an array of pointers
* to strings. Start with the buffer created above.
*/
n = 0;
n++;
if (n != 0)
return (ret);
return (PCICFG_SUCCESS);
}
static int
{
}
}
return (PCICFG_SUCCESS);
}
static int
{
}
}
return (PCICFG_SUCCESS);
}
/*
* Use cb%x,%x rather than pci%x,%x so that we can use specific cardbus
* drivers in /etc/driver_aliases if required
*/
static int
{
int ret;
#ifndef _DONT_USE_1275_GENERIC_NAMES
#endif
char *name;
char buffer[64];
char *compat[8];
int i, n;
/*
* NOTE: These are for both a child and PCI-PCI bridge node
*/
#ifndef _DONT_USE_1275_GENERIC_NAMES
#endif
/* Cardbus support */
} else {
}
if (subsysid != 0) {
} else {
}
/*
* In some environments, trying to use "generic" 1275 names is
* not the convention. In those cases use the name as created
* above. In all the rest of the cases, check to see if there
* is a generic name first.
*/
#ifdef _DONT_USE_1275_GENERIC_NAMES
#else
/*
* Set name to the above fabricated name
*/
}
#endif
/*
* The node name field needs to be filled in with the name
*/
return (PCICFG_FAILURE);
}
/*
* Create the compatible property as an array of pointers
* to strings. Start with the cb name.
*/
n = 0;
if (subsysid != 0) {
} else {
}
if (subsysid != 0) {
/*
* Add subsys numbers as pci compatible.
*/
}
/*
*/
/*
* Add in the Classcode
*/
return (ret);
}
for (i = 0; i < n; i++) {
}
return (PCICFG_SUCCESS);
}
/*
* Program the bus numbers into the bridge
*/
static void
{
/*
* Primary bus#
*/
/*
* Secondary bus#
*/
/*
* Set the subordinate bus number to ff in order to pass through any
* type 1 cycle with a bus number higher than the secondary bus#
* Note that this is reduced once the probe is complete in the
* cardbus_setup_bridge() function.
*/
}
static void
{
/*
* Enable memory, IO, bus mastership and error detection.
*/
"fast-back-to-back"))
/*
* ITE8888 Specific registers.
*/
}
static void
{
/*
* Enable back to back.
*/
if (stat & PCI_STAT_FBBC)
/*
* Reset the sub-ordinate bus.
*/
if (!(bctrl & PCI_BCNF_BCNTRL_RESET))
else
/*
* Enable error reporting.
*/
/*
* Enable back to back on secondary bus.
*/
if (stat & PCI_STAT_FBBC)
"enable_pci_pci_bridge stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
}
static int cardbus_reset_wait = 20;
static void
{
/*
* Don't mess with the command register on the cardbus bridge
* itself. This should have been done when it's parent
* did the setup. Some devices *require* certain things to
* disabled, this can be done using the "command-preserve"
* property and if we mess with it here it breaks that.
*
* comm |= (PCI_COMM_ME | PCI_COMM_PARITY_DETECT |
* PCI_COMM_SERR_ENABLE);
*/
/*
* Reset the sub-ordinate bus.
*/
if (!(bctrl & PCI_BCNF_BCNTRL_RESET))
else
/*
* Turn off pre-fetch.
*/
/*
* Enable error reporting.
*/
if (comm & PCI_COMM_PARITY_DETECT)
if (comm & PCI_COMM_SERR_ENABLE)
"enable_cardbus_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
/* after resetting the bridge, wait for everything to stablize */
}
static void
{
/*
* Turn off subordinate bus access.
*/
/*
* Disable error reporting.
*/
comm = 0;
"disable_pci_pci_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
}
static void
{
/*
* Turn off subordinate bus access.
*/
/*
* Disable error reporting.
*/
"disable_cardbus_bridge() stat 0x%04x comm 0x%04x bctrl 0x%04x\n",
}
static void
{
/*
* Enable memory, IO, bus mastership and error detection.
*/
"fast-back-to-back"))
}
static void
{
/*
* Turn off everything in the command register.
*/
}
#ifndef _DONT_USE_1275_GENERIC_NAMES
static char *
{
struct cardbus_name_entry *ptr;
}
}
return (NULL);
}
#endif /* _DONT_USE_1275_GENERIC_NAMES */
static void
{
int ret;
pname)) != DDI_SUCCESS) {
if (ret == DDI_PROP_NOT_FOUND)
"Failed to set boolean property "
"\"%s\"\n", pname);
}
}
static void
{
int ret;
if (ret == DDI_PROP_NOT_FOUND)
!= DDI_SUCCESS)
"Failed to set int property \"%s\"\n",
pname);
}
}
static void
{
int ret;
if (ret == DDI_PROP_NOT_FOUND)
"Failed to set string property "
"\"%s\" to \"%s\"\n",
}
}
static void
{
char c;
*dev = 0;
*func = 0;
while (c = *naddr++) {
if (c == ',') {
continue;
}
if (c >= '0' && c <= '9') {
} else if (c >= 'a' && c <= 'f') {
} else
break;
}
}
#ifdef DEBUG
static void
{
" Vendor ID = [0x%04x] "
"Device ID = [0x%04x]\n",
" Command REG = [0x%04x] "
"Status REG = [0x%04x]\n",
" Revision ID = [0x%02x] "
"Prog Class = [0x%02x]\n",
" Dev Class = [0x%02x] "
"Base Class = [0x%02x]\n",
" Cache LnSz = [0x%02x] "
"Latency Tmr = [0x%02x]\n",
" Header Type = [0x%02x] "
"BIST = [0x%02x]\n",
}
static void
{
" BASE 0 = [0x%08x] BASE 1 = [0x%08x]\n",
" BASE 2 = [0x%08x] BASE 3 = [0x%08x]\n",
" BASE 4 = [0x%08x] BASE 5 = [0x%08x]\n",
" Cardbus CIS = [0x%08x] ROM = [0x%08x]\n",
" Sub VID = [0x%04x] Sub SID = [0x%04x]\n",
" I Line = [0x%02x] I Pin = [0x%02x]\n",
" Max Grant = [0x%02x] Max Latent = [0x%02x]\n",
}
static void
{
if (header_type == PCI_HEADER_PPB) {
"........................................\n");
} else {
" Mem Base = [0x%08x] CBus Status = [0x%04x]\n",
}
" Pri Bus = [0x%02x] Sec Bus = [0x%02x]\n",
" Sub Bus = [0x%02x] Sec Latency = [0x%02x]\n",
switch (header_type) {
case PCI_HEADER_PPB:
" I/O Base LO = [0x%02x] I/O Lim LO = [0x%02x]\n",
" Sec. Status = [0x%04x]\n",
" Mem Base = [0x%04x] Mem Limit = [0x%04x]\n",
" PF Mem Base = [0x%04x] PF Mem Lim = [0x%04x]\n",
" PF Base HI = [0x%08x] PF Lim HI = [0x%08x]\n",
" I/O Base HI = [0x%04x] I/O Lim HI = [0x%04x]\n",
" ROM addr = [0x%08x]\n",
break;
case PCI_HEADER_CARDBUS:
" Mem Base 0 = [0x%08x] Mem Limit 0 = [0x%08x]\n",
" Mem Base 1 = [0x%08x] Mem Limit 1 = [0x%08x]\n",
" IO Base 0 = [0x%08x] IO Limit 0 = [0x%08x]\n",
" IO Base 1 = [0x%08x] IO Limit 1 = [0x%08x]\n",
break;
}
" Intr Line = [0x%02x] Intr Pin = [0x%02x]\n",
" Bridge Ctrl = [0x%04x]\n",
switch (header_type) {
case PCI_HEADER_CARDBUS:
" Sub VID = [0x%04x] Sub SID = [0x%04x]\n",
/* LATER: TI1250 only */
" Sys Control = [0x%08x]\n",
}
}
static void
{
else
}
static void
{
/* int rlen = nelems * sizeof(pci_regspec_t); */
"cardbus_dump_reg: \"reg\" has %d elements\n", nelems);
#if defined(CARDBUS_DEBUG)
if (cardbus_debug >= 1) {
int i;
for (i = 0; i < nelems; i++) {
"\t%d:%08x %08x %08x %08x %08x\n",
}
}
#endif
}
#endif
#if defined(CARDBUS_DEBUG)
void
{
}
void
{
}
#endif