示例#1
0
__initfunc(void prom_init(void *cif_handler, void *cif_stack))
{
	char buffer[80], *p;
	int ints[3];
	int node;
	int i = 0;

	prom_vers = PROM_P1275;

	prom_cif_init(cif_handler, cif_stack);

	prom_root_node = prom_getsibling(0);
	if((prom_root_node == 0) || (prom_root_node == -1))
		prom_halt();

	prom_chosen_node = prom_finddevice("/chosen");
	if (!prom_chosen_node || prom_chosen_node == -1)
		prom_halt();

	prom_stdin = prom_getint (prom_chosen_node, "stdin");
	prom_stdout = prom_getint (prom_chosen_node, "stdout");

	node = prom_finddevice("/openprom");
	if (!node || node == -1)
		prom_halt();

	prom_getstring (node, "version", buffer, sizeof (buffer));

	prom_printf ("\n");

	if (strncmp (buffer, "OBP ", 4))
		goto strange_version;

	/* Version field is expected to be 'OBP xx.yy.zz date...' */

	p = buffer + 4;
	while (p && isdigit(*p) && i < 3) {
		ints[i++] = simple_strtoul(p, NULL, 0);
		if ((p = strchr(p, '.')) != NULL)
			p++;
	}
	if (i != 3)
		goto strange_version;

	prom_rev = ints[1];
	prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];

	printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4);

	prom_meminit();

	prom_ranges_init();

	/* Initialization successful. */
	return;

strange_version:
	prom_printf ("Strange OBP version `%s'.\n", buffer);
	prom_halt ();
}
示例#2
0
/**
 * @brief Initializes the OpenBoot PROM interface on an early boot stage.
 * Before using any routines in the prom library, prom_init() must be
 * called. This should be one of the first things to be done on bootup,
 * since it provides the output sink and the prom version that it used
 * for feedback and debugging purposes.
 */
void prom_init() {

  node_chosen = prom_finddevice("/chosen");
  if (!node_chosen || (int) node_chosen == -1)
    prom_exit();

  if(prom_getprop(node_chosen, "stdout", &node_stdout,
      sizeof(node_stdout)) <= 0)
    node_stdout = 0;

  if(prom_getprop(node_stdin, "stdin", &node_stdin,
      sizeof(node_stdin)) <= 0)
    node_stdin = 0;

  node_root = prom_finddevice("/");
  if (!node_root || (int) node_root == -1) {
    printk("Error: / device not found.\n");
    prom_exit();
  }

  if(prom_getprop(node_root, "compatible", prom_subarch,
    sizeof(prom_subarch)) <= 0) {
    printk("Note: compatible property not set.\n");
    /* not important, we can check compatibility with the %ver register */
    strncpy(prom_subarch, "unknown", 7);
  }

  node_obp = prom_finddevice("/openprom");
  if (!node_obp || (int) node_obp == -1) {
    printk("Error: /openprom device not found.\n");
    prom_exit();
  }

  if(prom_getprop(node_obp, "version", prom_version,
    sizeof(prom_version)) <= 0) {
    printk("Error: /openprom version property not found.\n");
    prom_exit();
  }
  if(strncmp("OBP ", prom_version, 4)) {
    printk("Error: Unknown OpenPROM version.\n");
    prom_exit();
  }

  prom_getprop(node_chosen, "bootpath", prom_bootpath,
               sizeof(prom_bootpath));
  prom_getprop(node_chosen, "bootargs", prom_bootargs,
               sizeof(prom_bootargs));

  /* if we found stdout, we can now clear the screen for the boot messages */
  if(node_stdout != 0)
    clear_screen();
}
示例#3
0
/*
 * Hook for modifying the OS boot path.  This hook allows us to handle
 * device arguments that the OS can't handle.
 */
void
mangle_os_bootpath(char *bpath)
{
	pnode_t node;
	char *stripped_pathname;

	node = prom_finddevice(bpath);
	if (prom_devicetype(node, "network") == 0)
		return;

	/*
	 * The OS can't handle network device arguments
	 * eg: boot net:promiscuous,speed=100,duplex=full
	 * So, we remove any argument strings in the device
	 * pathname we hand off to the OS for network devices.
	 *
	 * Internally, within boot, bpath is used to access
	 * the device, but v2path (as the boot property "boot-path")
	 * is the pathname passed to the OS.
	 */

	stripped_pathname = kmem_alloc(OBP_MAXPATHLEN, 0);
	prom_strip_options(bpath, stripped_pathname);
	v2path = stripped_pathname;
}
/*
 * On ms-IIep all the interrupt registers, counters etc
 * are PCIC registers, so we need to map it early.
 */
static void
bootstrapIIep(void)
{
	extern struct sparc_bus_space_tag mainbus_space_tag;

	int node;
	bus_space_handle_t bh;
	pcireg_t id;

	if ((node = prom_opennode("/pci")) == 0
	    && (node = prom_finddevice("/pci")) == 0)
		panic("bootstrap: could not get pci "
		      "node from prom");

	if (bus_space_map2(&mainbus_space_tag,
			   (bus_addr_t)MSIIEP_PCIC_PA,
			   (bus_size_t)sizeof(struct msiiep_pcic_reg),
			   BUS_SPACE_MAP_LINEAR,
			   MSIIEP_PCIC_VA, &bh) != 0)
		panic("bootstrap: unable to map ms-IIep pcic registers");

	/* verify that it's PCIC */
	id = mspcic_read_4(pcic_id);

	if (PCI_VENDOR(id) != PCI_VENDOR_SUN
	    && PCI_PRODUCT(id) != PCI_PRODUCT_SUN_MS_IIep)
		panic("bootstrap: PCI id %08x", id);
}
示例#5
0
static void __init read_obp_memory(const char *property,
				   struct linux_prom64_registers *regs,
				   int *num_ents)
{
	int node = prom_finddevice("/memory");
	int prop_size = prom_getproplen(node, property);
	int ents, ret, i;

	ents = prop_size / sizeof(struct linux_prom64_registers);
	if (ents > MAX_BANKS) {
		prom_printf("The machine has more %s property entries than "
			    "this kernel can support (%d).\n",
			    property, MAX_BANKS);
		prom_halt();
	}

	ret = prom_getproperty(node, property, (char *) regs, prop_size);
	if (ret == -1) {
		prom_printf("Couldn't get %s property from /memory.\n");
		prom_halt();
	}

	/* Sanitize what we got from the firmware, by page aligning
	 * everything.
	 */
	for (i = 0; i < ents; i++) {
		unsigned long base, size;

		base = regs[i].phys_addr;
		size = regs[i].reg_size;

		size &= PAGE_MASK;
		if (base & ~PAGE_MASK) {
			unsigned long new_base = PAGE_ALIGN(base);

			size -= new_base - base;
			if ((long) size < 0L)
				size = 0UL;
			base = new_base;
		}
		if (size == 0UL) {
			/* If it is empty, simply get rid of it.
			 * This simplifies the logic of the other
			 * functions that process these arrays.
			 */
			memmove(&regs[i], &regs[i + 1],
				(ents - i - 1) * sizeof(regs[0]));
			i--;
			ents--;
			continue;
		}
		regs[i].phys_addr = base;
		regs[i].reg_size = size;
	}

	*num_ents = ents;

	sort(regs, ents, sizeof(struct linux_prom64_registers),
	     cmp_p64, NULL);
}
示例#6
0
enum prom_output_device
prom_query_output_device()
{
	int st_p;
	char propb[64];
	int propl;

	st_p = prom_inst2pkg(prom_stdout);
	propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
	if (propl >= 0 && propl == sizeof("display") &&
	    strncmp("display", propb, sizeof("display")) == 0)
		return PROMDEV_OSCREEN;
	if(strncmp("serial", propb, 6))
		return PROMDEV_O_UNK;
	/* FIXME: Is there any better way how to find out? */	
	memset(propb, 0, sizeof(propb));
	st_p = prom_finddevice ("/options");
	prom_getproperty(st_p, "output-device", propb, sizeof(propb));

	/*
	 * If we get here with propb == 'screen', we are on ttya, as
	 * the PROM defaulted to this due to 'no input device'.
	 */
	if (!strncmp(propb, "screen", 6))
		return PROMDEV_OTTYA;

	if (strncmp (propb, "tty", 3) || !propb[3])
		return PROMDEV_O_UNK;
	switch (propb[3]) {
		case 'a': return PROMDEV_OTTYA;
		case 'b': return PROMDEV_OTTYB;
		default: return PROMDEV_O_UNK;
	}
}
示例#7
0
/* Query for input device type */
enum prom_input_device
prom_query_input_device()
{
	int st_p;
	char propb[64];

	st_p = prom_inst2pkg(prom_stdin);
	if(prom_node_has_property(st_p, "keyboard"))
		return PROMDEV_IKBD;
	prom_getproperty(st_p, "device_type", propb, sizeof(propb));
	if(strncmp(propb, "serial", 6))
		return PROMDEV_I_UNK;
	/* FIXME: Is there any better way how to find out? */	
	memset(propb, 0, sizeof(propb));
	st_p = prom_finddevice ("/options");
	prom_getproperty(st_p, "input-device", propb, sizeof(propb));

	/*
	 * If we get here with propb == 'keyboard', we are on ttya, as
	 * the PROM defaulted to this due to 'no input device'.
	 */
	if (!strncmp(propb, "keyboard", 8))
		return PROMDEV_ITTYA;

	if (strncmp (propb, "tty", 3) || !propb[3])
		return PROMDEV_I_UNK;
	switch (propb[3]) {
		case 'a': return PROMDEV_ITTYA;
		case 'b': return PROMDEV_ITTYB;
		default: return PROMDEV_I_UNK;
	}
}
示例#8
0
/*
 * This routine returns B_TRUE if the bootpath corresponds to
 * IP over IB driver.
 *
 * The format of the bootpath for the IP over IB looks like
 * /pci@1f,700000/pci@1/ib@0:port=1,pkey=8001,protocol=ip
 *
 * The minor node portion "port=1,pkey=8001,protocol=ip" represents
 * IP over IB driver.
 */
static boolean_t
netboot_over_ib(char *bootpath)
{

	char		*temp;
	boolean_t	ret = B_FALSE;
	pnode_t		node = prom_finddevice(bootpath);
	int		len;
	char		devicetype[OBP_MAXDRVNAME];

	/* Is this IB node ? */
	len = prom_getproplen(node, OBP_DEVICETYPE);
	if (len <= 1 || len >= OBP_MAXDRVNAME)
		return (B_FALSE);

	(void) prom_getprop(node, OBP_DEVICETYPE, (caddr_t)devicetype);

	if (strncmp("ib", devicetype, 2) == 0) {
		/* Check for proper IP over IB string */
		if ((temp = strstr(bootpath, ":port=")) != NULL) {
			if ((temp = strstr(temp, ",pkey=")) != NULL)
				if ((temp = strstr(temp,
				    ",protocol=ip")) != NULL) {
					ret = B_TRUE;
				}
		}
	}
	return (ret);
}
示例#9
0
void
load_platform_drivers(void)
{
	dev_info_t 		*dip;		/* dip of the isa driver */
	pnode_t 		nodeid;

	/*
	 * Install ISA driver. This is required for the southbridge IDE
	 * workaround - to reset the IDE channel during IDE bus reset.
	 * Panic the system in case ISA driver could not be loaded or
	 * any problem in accessing its pci config space. Since the register
	 * to reset the channel for IDE is in ISA config space!.
	 */

	nodeid = prom_finddevice(ONTARIO_IDE_PATHNAME);
	if (nodeid == OBP_BADNODE) {
		return;
	}
	dip = e_ddi_hold_devi_by_path(ONTARIO_ISA_PATHNAME, 0);
	if (dip == NULL) {
		cmn_err(CE_PANIC, "Could not install the isa driver\n");
		return;
	}

	if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) {
		cmn_err(CE_PANIC, "Could not get the config space of isa\n");
		return;
	}
}
示例#10
0
/*
 * Returns the nodeid of /options.
 * Returns OBP_BADNODE if it doesn't exist.
 */
pnode_t
prom_optionsnode(void)
{
	static pnode_t node;

	if (node == 0)
		node = prom_finddevice("/options");
	return (node);
}
示例#11
0
void
ibd_init(void)
{
	pnode_t	chosen;
	char	*mtuprop = "ipib-frame-size";
	char	*bcastprop = "ipib-broadcast";
	char	*addrprop = "ipib-address";
	char	*cidprop = "client-id";
	int	cidlen;
	uint8_t	dhcpcid[DHCP_MAX_CID_LEN];

	mac_state.mac_addr_len = IPOIB_ADDRL;
	mac_state.mac_addr_buf = bkmem_alloc(mac_state.mac_addr_len);
	if (mac_state.mac_addr_buf == NULL)
		prom_panic("ibd_init: Cannot allocate memory.");

	chosen = prom_finddevice("/chosen");
	if (chosen == OBP_NONODE || chosen == OBP_BADNODE)
		prom_panic("ibd_init: Cannot find /chosen.");

	if (prom_getprop(chosen, addrprop, (caddr_t)mac_state.mac_addr_buf) !=
	    IPOIB_ADDRL)
		prom_panic("ibd_init: Cannot find /chosen:ipib-address\n.");

	if (prom_getprop(chosen, bcastprop, (caddr_t)&ibdbroadcastaddr) !=
	    IPOIB_ADDRL)
		prom_panic("ibd_init: Cannot find /chosen:ipib-broadcast\n.");

	if (((cidlen = prom_getproplen(chosen, cidprop)) <= 0) ||
	    (cidlen > DHCP_MAX_CID_LEN) || (prom_getprop(chosen, cidprop,
	    (caddr_t)&dhcpcid) != cidlen))
		prom_panic("ibd_init: Invalid /chosen:client-id\n.");
	dhcp_set_client_id(dhcpcid, cidlen);

	/*
	 * Note that prom reports mtu including 20 bytes of
	 * addressing information.
	 */
	if (prom_getprop(chosen, mtuprop,
	    (caddr_t)&mac_state.mac_mtu) <= 0)
		mac_state.mac_mtu = IBDSIZE + IPOIB_ADDRL;

	/*
	 * Tell upper layers that we can support a little
	 * more. We will be taking off these 20 bytes at
	 * the start before we invoke prom_write() to send
	 * over the wire.
	 */
	mac_state.mac_arp_timeout = IBD_ARP_TIMEOUT;
	mac_state.mac_in_timeout = IBD_IN_TIMEOUT;

	mac_state.mac_arp = ibd_arp;
	mac_state.mac_rarp = ibd_revarp;
	mac_state.mac_header_len = ibd_header_len;
	mac_state.mac_input = ibd_input;
	mac_state.mac_output = ibd_output;
}
示例#12
0
/*
 * Returns the nodeid of /aliases.
 * /aliases exists in OBP >= 2.4 and in Open Firmware.
 * Returns OBP_BADNODE if it doesn't exist.
 */
pnode_t
prom_alias_node(void)
{
	static pnode_t node;

	if (node == 0)
		node = prom_finddevice("/aliases");
	return (node);
}
示例#13
0
void __init prom_init(void *cif_handler, void *cif_stack)
{
	phandle node;

	prom_cif_init(cif_handler, cif_stack);

	prom_chosen_node = prom_finddevice(prom_chosen_path);
	if (!prom_chosen_node || (s32)prom_chosen_node == -1)
		prom_halt();

	prom_stdout = prom_getint(prom_chosen_node, "stdout");

	node = prom_finddevice("/openprom");
	if (!node || (s32)node == -1)
		prom_halt();

	prom_getstring(node, "version", prom_version, sizeof(prom_version));

	prom_printf("\n");
}
示例#14
0
int prom_get_mmu_ihandle(void)
{
	int node, ret;

	if (prom_mmu_ihandle_cache != 0)
		return prom_mmu_ihandle_cache;

	node = prom_finddevice(prom_chosen_path);
	ret = prom_getint(node, prom_mmu_name);
	if (ret == -1 || ret == 0)
		prom_mmu_ihandle_cache = -1;
	else
		prom_mmu_ihandle_cache = ret;

	return ret;
}
示例#15
0
int prom_get_mmu_ihandle(void)
{
    int node, ret;

    if (mmu_ihandle_cache != 0)
        return mmu_ihandle_cache;

    node = prom_finddevice("/chosen");
    ret = prom_getint(node, "mmu");
    if(ret == -1 || ret == 0)
        mmu_ihandle_cache = -1;
    else
        mmu_ihandle_cache = ret;

    return ret;
}
示例#16
0
static int prom_get_memory_ihandle(void)
{
	static int memory_ihandle_cache;
	int node, ret;

	if (memory_ihandle_cache != 0)
		return memory_ihandle_cache;

	node = prom_finddevice("/chosen");
	ret = prom_getint(node, "memory");
	if (ret == -1 || ret == 0)
		memory_ihandle_cache = -1;
	else
		memory_ihandle_cache = ret;

	return ret;
}
示例#17
0
boolean_t
is_netdev(char *devpath)
{
	pnode_t	node = prom_finddevice(devpath);
	char *options;

	if ((node == OBP_NONODE) || (node == OBP_BADNODE))
		return (B_FALSE);
	if (prom_devicetype(node, "network") != 0)
		return (B_TRUE);

	/*
	 * For Infiniband, network device names will be of the
	 * format XXX/ib@0:port=1,pkey=1234,protocol=ip[,YYY] where
	 * XXX is typically /pci@8,700000/pci@1. The device_type
	 * property will be "ib".
	 */
	if (prom_devicetype(node, "ib") != 0) {
		options = prom_path_options(devpath);
		if (options != NULL) {

#define	SEARCHSTRING	",protocol=ip"
#define	SEARCHSTRLEN	strlen(SEARCHSTRING)

			if (strstr(options, ",protocol=ip,") != NULL)
				return (B_TRUE);
			while ((options = strstr(options, SEARCHSTRING)) !=
			    NULL) {
				char nextc;

				nextc = options[SEARCHSTRLEN];
				if ((nextc == ',') || (nextc == 0))
					return (B_TRUE);
				options += SEARCHSTRLEN;
			}
		}
	}
	return (B_FALSE);
}
示例#18
0
文件: cfg.c 项目: arnew/yaboot
static int match_arch(const char *name)
{
	static prom_handle root;
	static char model[256], *p;

	if (!root) {
		if (!(root = prom_finddevice("/")))
			return 0;
	}

	if (!model[0]) {
		if (!prom_getprop(root, "compatible", model, sizeof(model)))
			return 0;
	}

	for (p = model; *p; p += strlen(p) + 1) {
		if (!strcasecmp(p, name))
			return 1;
	}

	return 0;
}
示例#19
0
/*
 * Return the devinfo node to a boot device
 */
static dev_info_t *
path_to_devinfo(char *path)
{
	struct i_path_findnode fn;
	extern dev_info_t *top_devinfo;

	/*
	 * Get the nodeid of the given pathname, if such a mapping exists.
	 */
	fn.dip = NULL;
	fn.nodeid = prom_finddevice(path);
	if (fn.nodeid != OBP_BADNODE) {
		/*
		 * Find the nodeid in our copy of the device tree and return
		 * whatever name we used to bind this node to a driver.
		 */
		ddi_walk_devs(top_devinfo, i_path_find_node, (void *)(&fn));
	}

#ifdef	DEBUG
	/*
	 * If we're bound to something other than the nodename,
	 * note that in the message buffer and system log.
	 */
	if (fn.dip) {
		char *p, *q;

		p = ddi_binding_name(fn.dip);
		q = ddi_node_name(fn.dip);
		if (p && q && (strcmp(p, q) != 0)) {
			BMDPRINTF(("path_to_devinfo: %s bound to %s\n",
			    path, p));
		}
	}
#endif	/* DEBUG */

	return (fn.dip);
}
示例#20
0
pnode_t
prom_chosennode(void)
{
	static pnode_t chosen;
	pnode_t	node;

	if (chosen)
		return (chosen);

	node = prom_finddevice("/chosen");

	if (node != OBP_BADNODE)
		return (chosen = node);

	prom_fatal_error("prom_chosennode: Can't find </chosen>\n");
	/*NOTREACHED*/

	/*
	 * gcc doesn't recognize "NOTREACHED" and puts the warning.
	 * To surpress it, returning an integer value is required.
	 */
	return ((pnode_t)0);
}
/*ARGSUSED*/
char *
kmdb_prom_get_ddi_prop(kmdb_auxv_t *kav, char *propname)
{
	pnode_t node;
	ssize_t len;
	char *val;

	if ((node = prom_finddevice("/options")) == NULL)
		return (NULL);

	if ((len = prom_getproplen(node, propname)) < 0)
		return (NULL);

	val = mdb_alloc(len + 1, UM_SLEEP);

	if (prom_bounded_getprop(node, propname, val, len) != len) {
		mdb_free(val, len);
		return (NULL);
	}
	val[len] = '\0';

	return (val);
}
示例#22
0
/*
 * translate a devfs pathname to one that will be acceptable
 * by the prom.  In most cases, there is no translation needed.
 * For systems supporting generically named devices, the prom
 * may support nodes such as 'disk' that do not have any unit
 * address information (i.e. target,lun info).  If this is the
 * case, the ddi framework will reject the node as invalid and
 * populate the devinfo tree with nodes froms the .conf file
 * (e.g. sd).  In this case, the names that show up in /devices
 * are sd - since the prom only knows about 'disk' nodes, this
 * routine detects this situation and does the conversion
 * There are also cases such as pluto where the disk node in the
 * prom is named "SUNW,ssd" but in /devices the name is "ssd".
 *
 * If MPxIO is enabled, the translation involves following
 * pathinfo nodes to the "best" parent.
 *
 * return a 0 on success with the new device string in ret_buf.
 * Otherwise return the appropriate error code as we may be called
 * from the openprom driver.
 */
int
i_devname_to_promname(char *dev_name, char *ret_buf, size_t len)
{
	dev_info_t *dip, *pdip, *cdip, *alt_dip = NULL;
	mdi_pathinfo_t *pip = NULL;
	char *dev_path, *prom_path;
	char *unit_address, *minorname, *nodename;
	major_t major;
	char *rptr, *optr, *offline;
	size_t olen, rlen;
	int circ;
	int ret = 0;

	/* do some sanity checks */
	if ((dev_name == NULL) || (ret_buf == NULL) ||
	    (strlen(dev_name) > MAXPATHLEN)) {
		return (EINVAL);
	}

	/*
	 * Convert to a /devices name. Fail the translation if
	 * the name doesn't exist.
	 */
	dev_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
	if (resolve_devfs_name(dev_name, dev_path) != 0 ||
	    strncmp(dev_path, "/devices/", 9) != 0) {
		kmem_free(dev_path, MAXPATHLEN);
		return (EINVAL);
	}
	dev_name = dev_path + sizeof ("/devices") - 1;

	bzero(ret_buf, len);

	if (prom_finddevice(dev_name) != OBP_BADNODE) {
		/* we are done */
		(void) snprintf(ret_buf, len, "%s", dev_name);
		kmem_free(dev_path, MAXPATHLEN);
		return (0);
	}

	/*
	 * if we get here, then some portion of the device path is
	 * not understood by the prom.  We need to look for alternate
	 * names (e.g. replace ssd by disk) and mpxio enabled devices.
	 */
	dip = e_ddi_hold_devi_by_path(dev_name, 0);
	if (dip == NULL) {
		cmn_err(CE_NOTE, "cannot find dip for %s", dev_name);
		kmem_free(dev_path, MAXPATHLEN);
		return (EINVAL);
	}

	prom_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
	rlen = len;
	rptr = ret_buf;

	if (!MDI_CLIENT(dip)) {
		ret = i_devi_to_promname(dip, prom_path, &alt_dip);
		if (ret == 0) {
			minorname = strrchr(dev_name, ':');
			if (minorname && (minorname[1] != '\0')) {
				(void) strcat(prom_path, minorname);
			}
			(void) snprintf(rptr, rlen, "%s", prom_path);
		}
	} else {
		/*
		 * if get to here, means dip is a vhci client
		 */
		offline = kmem_zalloc(len, KM_SLEEP); /* offline paths */
		olen = len;
		optr = offline;
		/*
		 * The following code assumes that the phci client is at leaf
		 * level.
		 */
		ndi_devi_enter(dip, &circ);
		while ((pip = mdi_get_next_phci_path(dip, pip)) != NULL) {
			/*
			 * walk all paths associated to the client node
			 */
			bzero(prom_path, MAXPATHLEN);

			/*
			 * replace with mdi_hold_path() when mpxio goes into
			 * genunix
			 */
			MDI_PI_LOCK(pip);
			MDI_PI_HOLD(pip);
			MDI_PI_UNLOCK(pip);

			if (mdi_pi_pathname_obp(pip, prom_path) != NULL) {
				/*
				 * The path has different obp path
				 */
				goto minor_pathinfo;
			}

			pdip = mdi_pi_get_phci(pip);
			ndi_hold_devi(pdip);

			/*
			 * Get obp path name of the phci node firstly.
			 * NOTE: if the alternate node of pdip exists,
			 * the third argument of the i_devi_to_promname()
			 * would be set to the alternate node.
			 */
			(void) i_devi_to_promname(pdip, prom_path, &alt_dip);
			if (alt_dip != NULL) {
				ndi_rele_devi(pdip);
				pdip = alt_dip;
				ndi_hold_devi(pdip);
			}

			nodename = ddi_node_name(dip);
			unit_address = MDI_PI(pip)->pi_addr;

			major = ddi_driver_major(dip);
			cdip = find_alternate_node(pdip, major);

			if (cdip) {
				nodename = ddi_node_name(cdip);
			}
			/*
			 * node name + unitaddr to the prom_path
			 */
			(void) strcat(prom_path, "/");
			(void) strcat(prom_path, nodename);
			if (unit_address && (*unit_address)) {
				(void) strcat(prom_path, "@");
				(void) strcat(prom_path, unit_address);
			}
			if (cdip) {
				/* hold from find_alternate_node */
				ndi_rele_devi(cdip);
			}
			ndi_rele_devi(pdip);
minor_pathinfo:
			minorname = strrchr(dev_name, ':');
			if (minorname && (minorname[1] != '\0')) {
				(void) strcat(prom_path, minorname);
			}

			if (MDI_PI_IS_ONLINE(pip)) {
				(void) snprintf(rptr, rlen, "%s", prom_path);
				rlen -= strlen(rptr) + 1;
				rptr += strlen(rptr) + 1;
				if (rlen <= 0) /* drop paths we can't store */
					break;
			} else {	/* path is offline */
				(void) snprintf(optr, olen, "%s", prom_path);
				olen -= strlen(optr) + 1;
				if (olen > 0) /* drop paths we can't store */
					optr += strlen(optr) + 1;
			}
			MDI_PI_LOCK(pip);
			MDI_PI_RELE(pip);
			if (MDI_PI(pip)->pi_ref_cnt == 0)
				cv_broadcast(&MDI_PI(pip)->pi_ref_cv);
			MDI_PI_UNLOCK(pip);
		}
		ndi_devi_exit(dip, circ);
		ret = 0;
		if (rlen > 0) {
			/* now add as much of offline to ret_buf as possible */
			bcopy(offline, rptr, rlen);
		}
		kmem_free(offline, len);
	}
	/* release hold from e_ddi_hold_devi_by_path() */
	ndi_rele_devi(dip);
	ret_buf[len - 1] = '\0';
	ret_buf[len - 2] = '\0';
	kmem_free(dev_path, MAXPATHLEN);
	kmem_free(prom_path, MAXPATHLEN);

	return (ret);
}
示例#23
0
/*
 *	SunOS and Solaris /dev/openprom ioctl calls.
 */
static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
				unsigned int cmd, unsigned long arg, int node)
{
	DATA *data = (DATA *) file->private_data;
	char buffer[OPROMMAXPARAM+1], *buf;
	struct openpromio *opp;
	unsigned long flags;
	int bufsize, len, error = 0;
	extern char saved_command_line[];
	static int cnt;

	if (cmd == OPROMSETOPT)
		bufsize = getstrings((void *)arg, &opp);
	else
		bufsize = copyin((void *)arg, &opp);

	if (bufsize < 0)
		return bufsize;

	switch (cmd) {
	case OPROMGETOPT:
	case OPROMGETPROP:
		save_and_cli(flags);
		len = prom_getproplen(node, opp->oprom_array);
		restore_flags(flags);

		if (len <= 0 || len > bufsize) {
			error = copyout((void *)arg, opp, sizeof(int));
			break;
		}

		save_and_cli(flags);
		len = prom_getproperty(node, opp->oprom_array, buffer, bufsize);
		restore_flags(flags);

		memcpy(opp->oprom_array, buffer, len);
		opp->oprom_array[len] = '\0';
		opp->oprom_size = len;

		error = copyout((void *)arg, opp, sizeof(int) + bufsize);
		break;

	case OPROMNXTOPT:
	case OPROMNXTPROP:
		save_and_cli(flags);
		buf = prom_nextprop(node, opp->oprom_array, buffer);
		restore_flags(flags);

		len = strlen(buf);
		if (len == 0 || len + 1 > bufsize) {
			error = copyout((void *)arg, opp, sizeof(int));
			break;
		}

		memcpy(opp->oprom_array, buf, len);
		opp->oprom_array[len] = '\0';
		opp->oprom_size = ++len;

		error = copyout((void *)arg, opp, sizeof(int) + bufsize);
		break;

	case OPROMSETOPT:
	case OPROMSETOPT2:
		buf = opp->oprom_array + strlen(opp->oprom_array) + 1;
		len = opp->oprom_array + bufsize - buf;

		save_and_cli(flags);
		error = prom_setprop(options_node, opp->oprom_array,
				     buf, len);
		restore_flags(flags);

		if (error < 0)
			error = -EINVAL;
		break;

	case OPROMNEXT:
	case OPROMCHILD:
	case OPROMSETCUR:
		if (bufsize < sizeof(int)) {
			error = -EINVAL;
			break;
		}

		node = *((int *) opp->oprom_array);

		save_and_cli(flags);
		switch (cmd) {
		case OPROMNEXT: node = __prom_getsibling(node); break;
		case OPROMCHILD: node = __prom_getchild(node); break;
		case OPROMSETCUR: break;
		}
		restore_flags(flags);

		data->current_node = node;
		*((int *)opp->oprom_array) = node;
		opp->oprom_size = sizeof(int);

		error = copyout((void *)arg, opp, bufsize + sizeof(int));
		break;

	case OPROMPCI2NODE:
		error = -EINVAL;

		if (bufsize >= 2*sizeof(int)) {
#ifdef CONFIG_PCI
			struct pci_dev *pdev;
			struct pcidev_cookie *pcp;
			pdev = pci_find_slot (((int *) opp->oprom_array)[0],
					      ((int *) opp->oprom_array)[1]);

			pcp = pdev->sysdata;
			if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) {
				node = pcp->prom_node;
				data->current_node = node;
				*((int *)opp->oprom_array) = node;
				opp->oprom_size = sizeof(int);
				error = copyout((void *)arg, opp, bufsize + sizeof(int));
			}
#endif
		}
		break;

	case OPROMPATH2NODE:
		save_and_cli(flags);
		node = prom_finddevice(opp->oprom_array);
		restore_flags(flags);
		data->current_node = node;
		*((int *)opp->oprom_array) = node;
		opp->oprom_size = sizeof(int);

		error = copyout((void *)arg, opp, bufsize + sizeof(int));
		break;

	case OPROMGETBOOTARGS:
		buf = saved_command_line;

		len = strlen(buf);

		if (len > bufsize) {
			error = -EINVAL;
			break;
		}

		strcpy(opp->oprom_array, buf);
		opp->oprom_size = len;

		error = copyout((void *)arg, opp, bufsize + sizeof(int));
		break;

	case OPROMU2P:
	case OPROMGETCONS:
	case OPROMGETFBNAME:
		if (cnt++ < 10)
			printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n");
		error = -EINVAL;
		break;
	default:
		if (cnt++ < 10)
			printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
		error = -EINVAL;
		break;
	}

	kfree(opp);
	return error;
}
示例#24
0
int
openpromioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
{
	struct opiocdesc *op;
	int node, optionsnode, len, ok, error, s;
	char *name, *value, *nextprop;

	optionsnode = prom_getoptionsnode();

	/* All too easy... */
	if (cmd == OPIOCGETOPTNODE) {
		*(int *)data = optionsnode;
		return (0);
	}

	/* Verify node id */
	op = (struct opiocdesc *)data;
	node = op->op_nodeid;
	if (node != 0 && node != lastnode && node != optionsnode) {
		/* Not an easy one, must search for it */
		s = splhigh();
		ok = openpromcheckid(findroot(), node);
		splx(s);
		if (!ok)
			return (EINVAL);
		lastnode = node;
	}

	name = value = NULL;
	error = 0;
	switch (cmd) {

	case OPIOCGET:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		s = splhigh();
		len = prom_proplen(node, name);
		splx(s);
		if (len > op->op_buflen) {
			error = ENOMEM;
			break;
		}
		op->op_buflen = len;
		/* -1 means no entry; 0 means no value */
		if (len <= 0)
			break;
		value = malloc(len, M_TEMP, M_WAITOK);
		s = splhigh();
		error = prom_getprop(node, name, 1, &len, &value);
		splx(s);
		if (error != 0)
			break;
		error = copyout(value, op->op_buf, len);
		break;

	case OPIOCSET:
		if ((flags & FWRITE) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		error = openpromgetstr(op->op_buflen, op->op_buf, &value);
		if (error)
			break;
		s = splhigh();
		len = prom_setprop(node, name, value, op->op_buflen + 1);
		splx(s);
		if (len != op->op_buflen)
			error = EINVAL;
		break;

	case OPIOCNEXTPROP:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		s = splhigh();
		nextprop = prom_nextprop(node, name);
		splx(s);
		len = strlen(nextprop);
		if (len > op->op_buflen)
			len = op->op_buflen;
		else
			op->op_buflen = len;
		error = copyout(nextprop, op->op_buf, len);
		break;

	case OPIOCGETNEXT:
		if ((flags & FREAD) == 0)
			return (EBADF);
		s = splhigh();
		node = nextsibling(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	case OPIOCGETCHILD:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		s = splhigh();
		node = firstchild(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	case OPIOCFINDDEVICE:
		if ((flags & FREAD) == 0)
			return (EBADF);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		node = prom_finddevice(name);
		if (node == 0 || node == -1) {
			error = ENOENT;
			break;
		}
		op->op_nodeid = lastnode = node;
		break;

	default:
		return (ENOTTY);
	}

	if (name)
		free(name, M_TEMP);
	if (value)
		free(value, M_TEMP);

	return (error);
}
示例#25
0
static void
get_bootpath_from_prom(void)
{
	struct btinfo_bootdev *bdev = NULL;
	char sbuf[OFPATHLEN], *cp;
	int chosen;

	/*
	 * Grab boot path from PROM
	 */
	if ((chosen = OF_finddevice("/chosen")) == -1)
		return;

	bdev = lookup_bootinfo(BTINFO_BOOTDEV);
	if (bdev != NULL) {
		strcpy(ofbootpath, bdev->name);
	} else {
		if (OF_getprop(chosen, "bootpath", sbuf, sizeof(sbuf)) < 0)
			return;
		strcpy(ofbootpath, sbuf);
	}
	DPRINTF(ACDB_BOOTDEV, ("bootpath: %s\n", ofbootpath));
	ofbootpackage = prom_finddevice(ofbootpath);

	/*
	 * Strip partition or boot protocol
	 */
	cp = strrchr(ofbootpath, ':');
	if (cp) {
		*cp = '\0';
		ofbootpartition = cp+1;
	}
	cp = strrchr(ofbootpath, '@');
	if (cp) {
		for (; cp != ofbootpath; cp--) {
			if (*cp == '/') {
				ofboottarget = cp+1;
				break;
			}
		}
	}

	DPRINTF(ACDB_BOOTDEV, ("bootpath phandle: 0x%x\n", ofbootpackage));
	DPRINTF(ACDB_BOOTDEV, ("boot target: %s\n",
	    ofboottarget ? ofboottarget : "<none>"));
	DPRINTF(ACDB_BOOTDEV, ("boot partition: %s\n",
	    ofbootpartition ? ofbootpartition : "<none>"));

	/* Setup pointer to boot flags */
	if (OF_getprop(chosen, "bootargs", sbuf, sizeof(sbuf)) == -1)
		return;
	strcpy(ofbootargs, sbuf);

	cp = ofbootargs;

	/* Find start of boot flags */
	while (*cp) {
		while(*cp == ' ' || *cp == '\t') cp++;
		if (*cp == '-' || *cp == '\0')
			break;
		while(*cp != ' ' && *cp != '\t' && *cp != '\0') cp++;
		if (*cp != '\0')
			*cp++ = '\0';
	}
	if (cp != ofbootargs)
		ofbootfile = ofbootargs;
	ofbootflags = cp;
	if (*cp != '-')
		return;

	for (;*++cp;) {
		int fl;

		fl = 0;
		BOOT_FLAG(*cp, fl);
		if (!fl) {
			printf("unknown option `%c'\n", *cp);
			continue;
		}
		boothowto |= fl;

		/* specialties */
		if (*cp == 'd') {
#if defined(KGDB)
			kgdb_break_at_attach = 1;
#elif defined(DDB)
			Debugger();
#else
			printf("kernel has no debugger\n");
#endif
		} else if (*cp == 't') {
			/* turn on traptrace w/o breaking into kdb */
			extern int trap_trace_dis;

			trap_trace_dis = 0;
		}
	}
}
示例#26
0
void __init prom_init(void *cif_handler, void *cif_stack)
{
	char buffer[80], *p;
	int ints[3];
	int node;
	int i = 0;
	int bufadjust;

	prom_vers = PROM_P1275;

	prom_cif_init(cif_handler, cif_stack);

	prom_root_node = prom_getsibling(0);
	if((prom_root_node == 0) || (prom_root_node == -1))
		prom_halt();

	prom_chosen_node = prom_finddevice("/chosen");
	if (!prom_chosen_node || prom_chosen_node == -1)
		prom_halt();

	prom_stdin = prom_getint (prom_chosen_node, "stdin");
	prom_stdout = prom_getint (prom_chosen_node, "stdout");

	node = prom_finddevice("/openprom");
	if (!node || node == -1)
		prom_halt();

	prom_getstring (node, "version", buffer, sizeof (buffer));

	prom_printf ("\n");

	if (strncmp (buffer, "OBP ", 4))
		goto strange_version;

	/*
	 * Version field is expected to be 'OBP xx.yy.zz date...'
	 * However, Sun can't stick to this format very well, so
	 * we need to check for 'OBP  xx.yy.zz date...' and adjust
	 * accordingly. -spot
	 */

	if (strncmp (buffer, "OBP  ", 5))
		bufadjust = 4;
	else
		bufadjust = 5;

	p = buffer + bufadjust;
	while (p && isdigit(*p) && i < 3) {
		ints[i++] = simple_strtoul(p, NULL, 0);
		if ((p = strchr(p, '.')) != NULL)
			p++;
	}
	if (i != 3)
		goto strange_version;

	prom_rev = ints[1];
	prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];

	printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);

	prom_meminit();

	/* Initialization successful. */
	return;

strange_version:
	prom_printf ("Strange OBP version `%s'.\n", buffer);
	prom_halt ();
}
/*
 * On sun4ms we have to do some nasty stuff here. We need to map
 * in the interrupt registers (since we need to find out where
 * they are from the PROM, since they aren't in a fixed place), and
 * disable all interrupts. We can't do this easily from locore
 * since the PROM is ugly to use from assembly. We also need to map
 * in the counter registers because we can't disable the level 14
 * (statclock) interrupt, so we need a handler early on (ugh).
 *
 * NOTE: We *demand* the psl to stay at splhigh() at least until
 * we get here. The system _cannot_ take interrupts until we map
 * the interrupt registers.
 */
static void
bootstrap4m(void)
{
	int node;
	int nvaddrs, *vaddrs, vstore[10];
	u_int pte;
	int i;
	extern void setpte4m(u_int, u_int);

	if ((node = prom_opennode("/obio/interrupt")) == 0
	    && (node = prom_finddevice("/obio/interrupt")) == 0)
		panic("bootstrap: could not get interrupt "
		      "node from prom");

	vaddrs = vstore;
	nvaddrs = sizeof(vstore)/sizeof(vstore[0]);
	if (prom_getprop(node, "address", sizeof(int),
		    &nvaddrs, &vaddrs) != 0) {
		printf("bootstrap: could not get interrupt properties");
		prom_halt();
	}
	if (nvaddrs < 2 || nvaddrs > 5) {
		printf("bootstrap: cannot handle %d interrupt regs\n",
		       nvaddrs);
		prom_halt();
	}

	for (i = 0; i < nvaddrs - 1; i++) {
		pte = getpte4m((u_int)vaddrs[i]);
		if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE) {
			panic("bootstrap: PROM has invalid mapping for "
			      "processor interrupt register %d",i);
			prom_halt();
		}
		pte |= PPROT_S;

		/* Duplicate existing mapping */
		setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte);
	}
	cpuinfo.intreg_4m = (struct icr_pi *)
		(PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(bootmid)));

	/*
	 * That was the processor register...now get system register;
	 * it is the last returned by the PROM
	 */
	pte = getpte4m((u_int)vaddrs[i]);
	if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
		panic("bootstrap: PROM has invalid mapping for system "
		      "interrupt register");
	pte |= PPROT_S;

	setpte4m(SI_INTR_VA, pte);

	/* Now disable interrupts */
	icr_si_bis(SINTR_MA);

	/* Send all interrupts to primary processor */
	*((u_int *)ICR_ITR) = CPU_MID2CPUNO(bootmid);

#ifdef DEBUG
/*	printf("SINTR: mask: 0x%x, pend: 0x%x\n", *(int*)ICR_SI_MASK,
	       *(int*)ICR_SI_PEND);
*/
#endif
}
示例#28
0
void check_if_starfire(void)
{
	int ssnode = prom_finddevice("/ssp-serial");
	if (ssnode != 0 && ssnode != -1)
		this_is_starfire = 1;
}
示例#29
0
static void __init read_obp_memory(const char *property,
				   struct linux_prom64_registers *regs,
				   int *num_ents)
{
	int node = prom_finddevice("/memory");
	int prop_size = prom_getproplen(node, property);
	int ents, ret, i;

	ents = prop_size / sizeof(struct linux_prom64_registers);
	if (ents > MAX_BANKS) {
		prom_printf("The machine has more %s property entries than "
			    "this kernel can support (%d).\n",
			    property, MAX_BANKS);
		prom_halt();
	}

	ret = prom_getproperty(node, property, (char *) regs, prop_size);
	if (ret == -1) {
		prom_printf("Couldn't get %s property from /memory.\n");
		prom_halt();
	}

	/* Sanitize what we got from the firmware, by page aligning
	 * everything.
	 */
	for (i = 0; i < ents; i++) {
		unsigned long base, size;

		base = regs[i].phys_addr;
		size = regs[i].reg_size;

		size &= PAGE_MASK;
		if (base & ~PAGE_MASK) {
			unsigned long new_base = PAGE_ALIGN(base);

			size -= new_base - base;
			if ((long) size < 0L)
				size = 0UL;
			base = new_base;
		}
		regs[i].phys_addr = base;
		regs[i].reg_size = size;
	}

	for (i = 0; i < ents; i++) {
		if (regs[i].reg_size == 0UL) {
			int j;

			for (j = i; j < ents - 1; j++) {
				regs[j].phys_addr =
					regs[j+1].phys_addr;
				regs[j].reg_size =
					regs[j+1].reg_size;
			}

			ents--;
			i--;
		}
	}

	*num_ents = ents;

	sort(regs, ents, sizeof(struct linux_prom64_registers),
	     cmp_p64, NULL);
}
示例#30
0
/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
	int node = 0;
	unsigned int iter, num_regs;

	node = prom_finddevice("/memory");
	num_regs = prom_getproperty(node, "available",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
	for(iter=0; iter<num_regs; iter++) {
		prom_phys_avail[iter].start_adr =
			prom_reg_memlist[iter].phys_addr;
		prom_phys_avail[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_phys_avail[iter].theres_more =
			&prom_phys_avail[iter+1];
	}
	prom_phys_avail[iter-1].theres_more = NULL;

	num_regs = prom_getproperty(node, "reg",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
	for(iter=0; iter<num_regs; iter++) {
		prom_phys_total[iter].start_adr =
			prom_reg_memlist[iter].phys_addr;
		prom_phys_total[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_phys_total[iter].theres_more =
			&prom_phys_total[iter+1];
	}
	prom_phys_total[iter-1].theres_more = NULL;

	node = prom_finddevice("/virtual-memory");
	num_regs = prom_getproperty(node, "available",
				    (char *) prom_reg_memlist,
				    sizeof(prom_reg_memlist));
	num_regs = (num_regs/sizeof(struct linux_prom64_registers));

	/* Convert available virtual areas to taken virtual
	 * areas.  First sort, then convert.
	 */
	for(iter=0; iter<num_regs; iter++) {
		prom_prom_taken[iter].start_adr =
			prom_reg_memlist[iter].phys_addr;
		prom_prom_taken[iter].num_bytes =
			prom_reg_memlist[iter].reg_size;
		prom_prom_taken[iter].theres_more =
			&prom_prom_taken[iter+1];
	}
	prom_prom_taken[iter-1].theres_more = NULL;

	prom_sortmemlist(prom_prom_taken);

	/* Finally, convert. */
	for(iter=0; iter<num_regs; iter++) {
		prom_prom_taken[iter].start_adr =
			prom_prom_taken[iter].start_adr +
			prom_prom_taken[iter].num_bytes;
		prom_prom_taken[iter].num_bytes =
			prom_prom_taken[iter+1].start_adr -
			prom_prom_taken[iter].start_adr;
	}
	prom_prom_taken[iter-1].num_bytes =
		-1UL - prom_prom_taken[iter-1].start_adr;

	/* Sort the other two lists. */
	prom_sortmemlist(prom_phys_total);
	prom_sortmemlist(prom_phys_avail);

	/* Link all the lists into the top-level descriptor. */
	prom_memlist.p1275_totphys=&prom_ptot_ptr;
	prom_memlist.p1275_prommap=&prom_ptak_ptr;
	prom_memlist.p1275_available=&prom_pavl_ptr;
}