root/sys/arch/sgimips/sgimips/autoconf.c
/*      $NetBSD: autoconf.c,v 1.46 2025/10/03 14:13:45 thorpej Exp $    */

/*
 * Copyright (c) 2000 Soren S. Jorvang
 * 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, 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *          This product includes software developed for the
 *          NetBSD Project.  See http://www.NetBSD.org/ for
 *          information about NetBSD.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.46 2025/10/03 14:13:45 thorpej Exp $");

#include "opt_ddb.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/device.h>

#include <machine/cpu.h>
#include <machine/sysconf.h>
#include <machine/machtype.h>
#include <machine/autoconf.h>
#include <machine/vmparam.h>    /* for PAGE_SIZE */

#include <dev/pci/pcivar.h>

#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsiconf.h>

static device_t booted_controller = NULL;
static int      booted_slot, booted_unit;
static const char       *booted_protocol = NULL;

extern struct platform platform;

void
cpu_configure(void)
{

        (void)splhigh();
        if (config_rootfound("mainbus", NULL) == NULL)
                panic("no mainbus found");

        /*
         * Clear latched bus error registers which may have been
         * caused by probes for non-existent devices.
         */
        (*platform.bus_reset)();

        /*
         * Hardware interrupts will be enabled in cpu_initclocks(9)
         * to avoid hardclock(9) by CPU INT5 before softclockintr is
         * initialized in initclocks().
         */
}

/*
 * Look at the string 'cp' and decode the boot device.  Boot names
 * can be something like 'bootp(0)netbsd' or
 * 'scsi(0)disk(1)rdisk(0)partition(0)netbsd' or
 * 'dksc(0,1,0)netbsd'
 */
void
makebootdev(const char *cp)
{
        if (booted_protocol != NULL)
                return;

        booted_slot = booted_unit = booted_partition = 0;

        if (strncmp(cp, "pci(", 4) == 0) {
                cp += 4;

                while (*cp && *cp != ')')
                    cp++;

                if (*cp != ')')
                    return;

                cp++;
        }

        if (strncmp(cp, "scsi(", 5) == 0) {
                cp += 5;
                if (*cp >= '0' && *cp <= '9')
                        booted_slot = *cp++ - '0';
                if (strncmp(cp, ")disk(", 6) == 0) {
                        cp += 6;
                        if (*cp >= '0' && *cp <= '9')
                                booted_unit = *cp++ - '0';
                }
                /* XXX can rdisk() ever be other than 0? */
                if (strncmp(cp, ")rdisk(0)partition(", 19) == 0) {
                        cp += 19;
                        while (*cp >= '0' && *cp <= '9')
                                booted_partition =
                                        booted_partition * 10 + *cp++ - '0';
                }
                if (*cp != ')')
                        return; /* XXX ? */
                booted_protocol = "SCSI";
                return;
        }
        if (strncmp(cp, "dksc(", 5) == 0) {
                cp += 5;
                if (*cp >= '0' && *cp <= '9')
                        booted_slot = *cp++ - '0';
                if (*cp == ',') {
                        ++cp;
                        if (*cp >= '0' || *cp <= '9')
                                booted_unit = *cp++ - '0';
                        if (*cp == ',') {
                                ++cp;
                                if (*cp >= '0' && *cp <= '9')
                                        booted_partition = *cp++ - '0';
                        }
                }
                if (*cp != ')')
                        return;         /* XXX ??? */
                booted_protocol = "SCSI";
                return;
        }
        if (strncmp(cp, "bootp(", 6) == 0) {
                /* XXX controller number?  Needed to
                   handle > 1 network controller */
                booted_protocol = "BOOTP";
                return;
        }
}

void
cpu_rootconf(void)
{
        printf("boot device: %s\n",
                booted_device ? device_xname(booted_device) : "<unknown>");

        rootconf();
}

/*
 * Try to determine the boot device and set up some device properties
 * to handle machine dependent quirks.
 */

#define BUILTIN_AHC_P(pa)       \
    (((pa)->pa_bus == 0 && (pa)->pa_device == 1 && (pa)->pa_function == 0) || \
     ((pa)->pa_bus == 0 && (pa)->pa_device == 2 && (pa)->pa_function == 0))

void
device_register(device_t dev, void *aux)
{
        static int found, initted, scsiboot, netboot;
        device_t parent = device_parent(dev);

        if (mach_type == MACH_SGI_IP32 &&
            parent != NULL && device_is_a(parent, "pci")) {
                struct pci_attach_args *pa = aux;

                if (BUILTIN_AHC_P(pa)) {
                        if (! device_setprop_bool(dev,
                                        "aic7xxx-use-target-defaults", true)) {
                                printf("WARNING: unable to set "
                                    "aic7xxx-use-target-defaults property "
                                    "for %s\n", device_xname(dev));
                        }

                        if (! device_setprop_bool(dev,
                                        "aic7xxx-override-ultra", true)) {
                                printf("WARNING: unable to set "
                                    "aic7xxx-override-ultra property for %s\n",
                                    device_xname(dev));
                        }
                }
        }

        /*
         * The Set Engineering GIO Fast Ethernet controller has restrictions
         * on DMA boundaries.
         */
        if (device_is_a(dev, "tl")) {
                device_t grandparent;
                prop_number_t gfe_boundary;

                grandparent = device_parent(parent);
                if (grandparent != NULL && device_is_a(grandparent, "giopci")) {
                        gfe_boundary = prop_number_create_integer(PAGE_SIZE);
                        KASSERT(gfe_boundary != NULL);

                        if (prop_dictionary_set(device_properties(dev),
                            "tl-dma-page-boundary", gfe_boundary) == false) {
                                printf("WARNING: unable to set "
                                    "tl-dma-page-boundary property "
                                    "for %s\n", device_xname(dev));
                        }
                        prop_object_release(gfe_boundary);
                        return;
                }
        }

        if (found)
                return;

        if (!initted && booted_protocol) {
                scsiboot = strcmp(booted_protocol, "SCSI") == 0;
                netboot = (strcmp(booted_protocol, "BOOTP") == 0);
                initted = 1;
        }

        /*
         * Handle SCSI boot device definitions
         * wdsc -- IP12/22/24
         * ahc -- IP32
         */
        if ( (scsiboot && device_is_a(dev, "wdsc")) ||
             (scsiboot && device_is_a(dev, "ahc")) ) {
                /* XXX device_unit() abuse */
                if (device_unit(dev) == booted_slot)
                        booted_controller = dev;
                return;
        }

        /*
         * If we found the boot controller, if check disk/tape/cdrom device
         * on that controller matches.
         */
        if (booted_controller &&
            (device_is_a(dev, "sd") ||
             device_is_a(dev, "st") ||
             device_is_a(dev, "cd"))) {
                struct scsipibus_attach_args *sa = aux;

                if (device_parent(parent) != booted_controller)
                        return;
                if (booted_unit != sa->sa_periph->periph_target)
                        return;
                booted_device = dev;
                found = 1;
                return;
        }

        /*
         * Check if netboot device.
         */
        if (netboot &&
            (device_is_a(dev, "sq") ||
             device_is_a(dev, "mec"))) {
                /* XXX Check unit number? (Which we don't parse yet) */
                booted_device = dev;
                found = 1;
                return;
        }
}