ddi_impl.c revision 6bc8bc6a97518e9ec3d440de43fc1a30a7db825f
* Determine if an FPU is attached FP hardware exhibits Pentium floating point divide problem\n");
printf(
"FP hardware will not be used\n");
printf(
"No FPU in configuration\n");
* Initialize devices on the machine. * Uses configuration tree built by the PROMs to determine what * is present, and builds a tree of prototype dev_info nodes * corresponding to the hardware which identified itself. * Check for disabled drivers and initialize root node. * attach the isa nexus to get ACPI resource usage * isa is "kind of" a pseudo node /* reprogram devices not set up by firmware (BIOS) */ #
endif /* !SAS && !MPSAS */ * The "status" property indicates the operational status of a device. * If this property is present, the value is a string indicating the * status of the device as follows: * "disabled" not operational, but might become operational. * "fail" not operational because a fault has been detected, * and it is unlikely that the device will become * operational without repair. no additional details * "fail-xxx" not operational because a fault has been detected, * and it is unlikely that the device will become * operational without repair. "xxx" is additional * human-readable information about the particular * fault condition that was detected. * The absence of this property means that the operational status is * This routine checks the status property of the specified device node * and returns 0 if the operational status indicates failure, and 1 otherwise. * The property may exist on plug-in cards the existed before IEEE 1275-1994. * And, in that case, the property may not even be a string. So we carefully * check for the value "fail", in the beginning of the string, noting static const char *
status =
"status";
static const char *
fail =
"fail";
* Get the proplen ... if it's smaller than "fail", * or doesn't exist ... then we don't care, since * the value can't begin with the char string "fail". * NB: proplen, if it's a string, includes the NULL in the * the size of the property, and fail_len does not. * if a buffer was provided, use it * Get the property into the buffer, to the extent of the buffer, * and in case the buffer is smaller than the property size, * NULL terminate the buffer. (This handles the case where * a buffer was passed in and the caller wants to print the * value, but the buffer was too small). * If the value begins with the char string "fail", * then it means the node is failed. We don't care * about any other values. We assume the node is ok * although it might be 'disabled'. * Check the status of the device node passed as an argument. * if ((status is OKAY) || (status is DISABLED)) * print a warning and return DDI_FAILURE * a status property indicating bad memory will be associated * with a node which has a "device_type" property with a value of * "memory-controller". in this situation, return DDI_SUCCESS * print the status property information * Allow for implementation specific correction of PROM property values. * There are no adjustments needed in this implementation. * For the x86, we're prepared to claim that the interrupt string * is in the form of a list of <ipl,vec> specifications. "bad interrupt spec from %s%d - ipl %d, irq %d\n";
* determine if the driver is expecting the new style "interrupts" * property which just contains the IRQ, or the old style which * contains pairs of <IPL,IRQ>. if it is the new style, we always * assign IPL 5 unless an "interrupt-priorities" property exists. * in that case, the "interrupt-priorities" property contains the * IPL values that match, one for one, the IRQ values in the /* the old style "interrupts" property... */ * The list consists of <ipl,vec> elements if ((n = (*
in++ >>
1)) <
1)
* irq 2 on the PC bus is tied to irq 9 * on ISA, EISA and MicroChannel /* the new style "interrupts" property... */ * The list consists of <vec> elements /* XXX check for "interrupt-priorities" property... */ if (n != (
got_len /
sizeof (
int))) {
"bad interrupt-priorities length" " from %s%d: expected %d, got %d\n",
* irq 2 on the PC bus is tied to irq 9 * on ISA, EISA and MicroChannel * Create a ddi_parent_private_data structure from the ddi properties of * The "reg" and either an "intr" or "interrupts" properties are required * if the driver wishes to create mappings or field interrupts on behalf * The "reg" property is assumed to be a list of at least one triple * <bustype, address, size>*1 * The "intr" property is assumed to be a list of at least one duple * The "interrupts" property is assumed to be a list of at least one * n-tuples that describes the interrupt capabilities of the bus the device * is connected to. For SBus, this looks like * (This property obsoletes the 'intr' property). * The "ranges" property is optional. * Handle the 'reg' property. * See if I have a range (adding one where needed - this * means to add one for sbus node in sun4c, when romvec > 0, * if no range is already defined in the PROM node. * (Currently no sun4c PROMS define range properties, * but they should and may in the future.) For the SBus * node, the range is defined by the SBus reg property. * Handle the 'intr' and 'interrupts' properties * For backwards compatibility * we first look for the 'intr' property for the device. * If we're to support bus adapters and future platforms cleanly, * we need to support the generalized 'interrupts' property. * If both 'intr' and 'interrupts' are defined, * then 'interrupts' wins and we toss the 'intr' away. * Translate the 'intr' property into an array * an array of struct intrspec's. There's not really * very much to do here except copy what's out there. * Translate the 'interrupts' property into an array * of intrspecs for the rest of the DDI framework to * toy with. Only our ancestors really know how to * do this, so ask 'em. We massage the 'interrupts' * property so that it is pre-pended by a count of * the number of integers in the argument. "Unable to translate 'interrupts' for %s%d\n",
* Fill in parent-private data and this function returns to us * an indication if it used "registers" to fill in the data. * Called from the bus_ctl op of sunbus (sbus, obio, etc) nexus drivers * to implement the DDI_CTLOPS_INITCHILD operation. That is, it names * the children of sun busses based on the reg spec. * Handles the following properties (in make_ddi_ppd): * intr old-form interrupt spec * interrupts new (bus-oriented) interrupt spec * Name the child, also makes parent private data * Attempt to merge a .conf node; if successful, remove the * Return failure to remove node * Note that kmem_free is used here (instead of * ddi_prop_free) because the contents of the * property were placed into a separate buffer and * mucked with a bit before being stored in par_intr. * The actual return value from the prop lookup * was freed with ddi_prop_free previously. * Strip the node to properly convert it back to prototype form * turn this on to force isa, eisa, and mca device to ignore the new * hardware nodes in the device tree (normally turned on only for * drivers that need it by setting the property "ignore-hardware-nodes" * 7/31/96 -- Turned off globally. Leaving variable in for the moment * New DDI interrupt framework * This is the interrupt operator function wrapper for the bus function /* request parent to process this interrupt op */ "for %s%d due to down-rev nexus driver %s%d",
* i_ddi_add_softint - allocate and add a soft interrupt to the system /* add soft interrupt handler */ * The way this works is that it first tries to add a softint vector * at the new priority in hdlp. If that succeeds; then it removes the * existing softint vector at the old priority. * If a softint is pending at the old priority then fail the request. * Support for allocating DMAable memory to implement * ddi_dma_mem_alloc(9F) interface. * Dummy DMA attribute template for kmem_io[].kmem_io_attr. We only * care about addr_lo, addr_hi, and align. addr_hi will be dynamically set. 0x0000000000000000ULL,
/* dma_attr_addr_lo */ 0x0000000000000000ULL,
/* dma_attr_addr_hi */ 0x1000,
/* dma_attr_align */ 1,
1,
0xffffffffULL,
0xffffffffULL,
0x1,
1, 0
/* kmem io memory ranges and indices */ static int kmem_io_idx;
/* index of first populated kmem_io[] */ * Return the index of the highest memory range for addr. panic(
"kmem_io_index: invalid addr - must be at least 16m");
* Return the index of the next kmem_io populated memory range * allow kmem to be mapped in with different PTE cache attribute settings. * Used by i_ddi_mem_alloc() * initialize kmem_io[] arena/cache corresponding to * maxphysaddr and to the "common" io memory ranges that * have io_initial set to a non-zero value. * get contig size by addr * allocates contiguous memory to satisfy the 'size' and dma attributes * Not all of memory need to be physically contiguous if the * scatter-gather list length is greater than 1. /* 4k req gets from freelists rather than pfn search */ panic(
"contig_free: contig pp not found");
panic(
"contig_free: page freed");
* Allocate from the system, aligned on a specific boundary. * The alignment, if non-zero, must be a power of 2. * All of our allocators guarantee 16-byte alignment, so we don't * need to reserve additional space for the header. * To simplify picking the correct kmem_io_cache, we round up to * a multiple of KA_ALIGN. * System does not have memory in the requested range. * Try smaller kmem io ranges and larger cache sizes * to see if there might be memory available in /* now try the larger kmem io cache sizes */ * Check if the specified cache attribute is supported on the platform. * This function must be called before i_ddi_cacheattr_to_hatacc(). * The cache attributes are mutually exclusive. Any combination of * the attributes leads to a failure. /* All cache attributes are supported on X86/X64 */ /* undefined attributes */ /* set HAT cache attributes from the cache attributes */ static char *
fname =
"i_ddi_cacheattr_to_hatacc";
* If write-combining is not supported, then it falls back * set HAT attrs according to the cache attrs. * This case must not occur because the cache attribute is scrutinized * before this function is called. * set cacheable to hat attrs. * This should actually be called i_ddi_dma_mem_alloc. There should * also be an i_ddi_pio_mem_alloc. i_ddi_dma_mem_alloc should call * through the device tree with the DDI_CTLOPS_DMA_ALIGN ctl ops to * get alignment requirements for DMA memory. i_ddi_pio_mem_alloc * should use DDI_CTLOPS_PIO_ALIGN. Since we only have i_ddi_mem_alloc * so far which is used for both, DMA and PIO, we have to use the DMA * ctl ops to make everybody happy. * Check legality of arguments * figure out most restrictive alignment requirement * if we allocate memory with IOMEM_DATA_UNCACHED or * IOMEM_DATA_UC_WR_COMBINE, make sure we allocate a page aligned * memory that ends on a page boundry. * Don't want to have to different cache mappings to the same * Determine if we need to satisfy the request for physically * contiguous memory or alignments larger than pagesize. * verify that the minimum contig requirement for the * actual length does not cross segment boundary. * Allocate the requested amount from the system. * if we to modify the cache attributes, go back and muck with the * initialize access handle * covert old DMA limits structure to DMA attribute structure * set up DMA attribute structure to pass to i_ddi_mem_alloc() * if we modified the cache attributes on alloc, go back and * fix them since this memory could be returned to the "override cache attrs, memory leaked\n");
* Implementation instance override functions * Do not persist instance numbers assigned to devices in dom0 * Don't know how to power off i86pc. * Copy name to property_name, since name * is in the low address range below kernelbase. "boot property string is truncated to %s",
kern_str);
* Import "root" properties from the boot. * We do this by invoking BOP_NEXTPROP until the list * is completely copied in. /* copy string to memory above kernelbase */ * Skip vga properties. They will be picked up later "boot property %s longer than 0x%x, ignored\n",
* si-machine, si-hw-provider * goes to kernel data structures. * bios-boot-device and stdout * goes to hardware property list so it may show up * in the prtconf -vp output. This is needed by }
else if (
strcmp(
name,
"bios-boot-device") == 0) {
/* Property type unknown, use old prop interface */ * There really needs to be a better way for identifying various * console framebuffers and their related issues. Till then, * check for this one as a replacement to vgatext. * Import "vga" properties from the boot. name =
"display-edif-block";
* kdmconfig is also looking for display-type and * video-adapter-type. We default to color and svga. * Could it be "monochrome", "vga"? * Nah, you've got to come to the 21st century... * And you can set monitor type manually in kdmconfig * if you are really an old junky. devi,
"display-type",
"color");
devi,
"video-adapter-type",
"svga");
name =
"display-edif-id";
* This is temporary, but absolutely necessary. If we are being * booted with a device tree created by the DevConf project's bootconf * program, then we have device information nodes that reflect * reality. At this point in time in the Solaris release schedule, the * kernel drivers aren't prepared for reality. They still depend on their * own ad-hoc interpretations of the properties created when their .conf * files were interpreted. These drivers use an "ignore-hardware-nodes" * property to prevent them from using the nodes passed up from the bootconf * Trying to assemble root file system drivers as we are booting from * devconf will fail if the kernel driver is basing its name_addr's on the * psuedo-node device info while the bootpath passed up from bootconf is using * reality-based name_addrs. We help the boot along in this case by * looking at the pre-bootconf bootpath and determining if we would have * successfully matched if that had been the bootpath we had chosen. * Note that we only even perform this extra check if we've booted * using bootconf's 1275 compliant bootpath, this is the boot device, and * we're trying to match the name_addr specified in the 1275 bootpath. * There are multiple criteria to be met before we can even * consider allowing a name_addr match here. * 1) We must have been booted such that the bootconf program * created device tree nodes and properties. This can be * determined by examining the 'bootpath' property. This * property will be a non-null string iff bootconf was * 2) The module that we want to match must be the boot device. * 3) The instance of the module we are thinking of letting be * our match must be ignoring hardware nodes. * 4) The name_addr we want to match must be the name_addr * specified in the 1275 bootpath. "ignore-hardware-nodes", -
1) != -
1)) {
* We didn't boot from bootconf so we never need to * do any special matches. * No fallback position for matching. This is * certainly unexpected, but we'll handle it * Determine boot device module and 1275 name_addr * bootpath assumed to be of the form /bus/module@name_addr * Determine fallback name_addr * 10/3/96 - Also save fallback module name because it * might actually be different than the current module * name. E.G., ISA pnp drivers have new names. * bootpath assumed to be of the form /bus/module@name_addr /* Free up the bootpath storage now that we're done with it. */ "ignore-hardware-nodes", -
1) != -
1) ||
* Perform a copy from a memory mapped device (whose devinfo pointer is devi) * separately mapped at devaddr in the kernel to a kernel buffer at kaddr. * Perform a copy to a memory mapped device (whose devinfo pointer is devi) * separately mapped at devaddr in the kernel from a kernel buffer at kaddr. /* Set up protected environment. */ /* Take down protected environment. */ * This is called only to process peek/poke when the DIP is NULL. * Assume that this is for memory, as nexi take care of device safe accesses. * we've just done a cautious put/get. Check if it was successful by * calling pci_ereport_post() on all puts and for any gets that return -1 * for a cautious put or get or a non-cautious get that returned -1 call * io framework to see if there really was an error * We only get here with DDI_DEFAULT_ACC for config space gets. * Non-hardened drivers may be probing the hardware and * expecting -1 returned. So need to treat errors on * DDI_DEFAULT_ACC as DDI_FM_ERR_EXPECTED. * Hardened driver doing protected accesses shouldn't * get errors unless there's a hardware problem. Treat * as nonfatal if there's an error, but set UNEXPECTED * so we raise ereports on any errors and potentially * pci_peekpoke_check_nofma() is for when an error occurs on a register access * during pci_ereport_post(). We can't call pci_ereport_post() again or we'd * recurse, so assume all puts are OK and gets have failed if they return -1 * this function only supports cautious accesses, not peeks/pokes * which don't have a handle * As this may be a recursive call from within * pci_ereport_post() we can't wait for the mutexes. * Fortunately we know someone is already calling * pci_ereport_post() which will handle the error bits * for us, and as this is a config space access we can * just do the access and check return value for -1 * using pci_peekpoke_check_nofma(). * This can't be a recursive call. Drop the err_mutex and get * both mutexes in the right order. If an error hasn't already * been detected by the ontrap code, use pci_peekpoke_check_fma * which will call pci_ereport_post() to check error status. * Read in the properties from the boot. /* do bus dependent probes. */ /* not framebuffer should be enumerated, if present */ * Precedence given to rootdev if set in /etc/system * Usually rootfs.bo_name is initialized by the * the bootpath property from bootenv.rc, but * defaults to "/ramdisk:a" otherwise. * Modload the prom simulator, then let it probe to verify existence * and type of PCI support. /* load modules to install bus probes */ if (
modload(
"misc",
"pci_autoconfig") < 0) {
(
void)
modload(
"misc",
"xpv_autoconfig");
if (
modload(
"misc",
"pci_autoconfig") < 0) {
/* run the probe functions */ * Reprogram devices not set up by firmware. /* run the probe function */ * The following functions ready a cautious request to go up to the nexus * driver. It is up to the nexus driver to decide how to process the request. * returns the maximum DMA size which can be performed in a single DMA * window taking into account the devices DMA contraints (attrp), the * maximum copy buffer size (if applicable), and the worse case buffer * take the min of maxxfer and the the worse case fragementation * (e.g. every cookie <= 1 page) * If the DMA engine can't reach all off memory, we also need to take * the max size of the copybuf into consideration. * we only return a 32-bit value. Make sure it's not -1. Round to a * page so it won't be mistaken for an error value during debug. * make sure the value we return is a whole multiple of the