void
pcmu_pbm_create(pcmu_t *pcmu_p)
{
	pcmu_pbm_t *pcbm_p;
	int len;
	dev_info_t *dip = pcmu_p->pcmu_dip;

	/*
	 * Allocate a state structure for the PBM and cross-link it
	 * to its per pci node state structure.
	 */
	pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP);
	pcmu_p->pcmu_pcbm_p = pcbm_p;
	pcbm_p->pcbm_pcmu_p = pcmu_p;

	len = snprintf(pcbm_p->pcbm_nameinst_str,
	    sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip));
	pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len;
	(void) snprintf(pcbm_p->pcbm_nameaddr_str,
	    sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip));

	pcmu_pbm_setup(pcbm_p);

	PCMU_DBG4(PCMU_DBG_ATTACH, dip,
	    "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n",
	    pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg,
	    pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg);
	PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n",
	    pcbm_p->pcbm_config_header);

	/*
	 * Register a function to disable pbm error interrupts during a panic.
	 */
	bus_func_register(BF_TYPE_ERRDIS,
	    (busfunc_t)pcmu_pbm_disable_errors, pcbm_p);

	/*
	 * create the interrupt-priorities property if it doesn't
	 * already exist to provide a hint as to the PIL level for
	 * our interrupt.
	 */
	if (ddi_getproplen(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "interrupt-priorities",
	    &len) != DDI_PROP_SUCCESS) {
		/* Create the interrupt-priorities property. */
		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
		    DDI_PROP_CANSLEEP, "interrupt-priorities",
		    (caddr_t)pcmu_pil, sizeof (pcmu_pil));
	}
	pcmu_pbm_configure(pcbm_p);
}
Example #2
0
static int
ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
	dev_info_t	*cdip = rdip;
	pci_regspec_t	*pci_rp;
	int		reglen, len;
	uint32_t	d, intr;

	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
	    (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
		goto done;

	/*
	 * If the interrupt-map property is defined at this
	 * node, it will have performed the interrupt
	 * translation as part of the property, so no
	 * rotation needs to be done.
	 */
	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "interrupt-map", &len) == DDI_PROP_SUCCESS)
		goto done;

	cdip = get_my_childs_dip(dip, rdip);

	/*
	 * Use the devices reg property to determine its
	 * PCI bus number and device number.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
		return (DDI_FAILURE);

	intr = hdlp->ih_vector;

	/* Spin the interrupt */
	d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);

	if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
		hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
	else
		cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
		    ddi_driver_name(rdip), ddi_get_instance(rdip),
		    ddi_driver_name(dip), intr);

	kmem_free(pci_rp, reglen);

done:
	/* Pass up the request to our parent. */
	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
}
Example #3
0
/*ARGSUSED*/
static int
fco_getproplen(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
{
	int proplen;
	int flags = 0;
	fc_phandle_t h;
	dev_info_t *dip;
	char *pnp;
	char propname[OBP_MAXPROPNAME];

	if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
		flags |= DDI_PROP_DONTPASS;

	if (fc_cell2int(cp->nargs) != 2)
		return (fc_syntax_error(cp, "nargs must be 2"));

	if (fc_cell2int(cp->nresults) < 1)
		return (fc_syntax_error(cp, "nresults must be > 0"));

	/*
	 * Make sure this is a handle we gave out ...
	 */
	h = fc_cell2phandle(fc_arg(cp, 0));
	if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
		return (fc_priv_error(cp, "unknown handle"));

	/*
	 * XXX: We should care if the string is longer than OBP_MAXPROPNAME
	 */
	pnp = fc_cell2ptr(fc_arg(cp, 1));
	bzero(propname, OBP_MAXPROPNAME);
	if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
		return (fc_priv_error(cp, "EFAULT copying in propname"));

	if (ddi_getproplen(DDI_DEV_T_ANY, dip, flags, propname, &proplen))
		proplen = -1;

	fc_result(cp, 0) = fc_int2cell(proplen);
	cp->nresults = fc_int2cell(1);
	return (fc_success_op(ap, rp, cp));
}
Example #4
0
/*
 * If we don't already have a master SBBC selected,
 * get the <sbbc> property from the /chosen node. If
 * the pathname matches, this is the master SBBC and
 * we set up the console/TOD SRAM mapping here.
 */
static void
sbbc_chosen_init(sbbc_softstate_t *softsp)
{
	char		master_sbbc[MAXNAMELEN];
	char		pn[MAXNAMELEN];
	int		nodeid, len;
	pnode_t		dnode;

	if (master_chosen != FALSE) {
		/*
		 * We've got one already
		 */
		return;
	}

	/*
	 * Get /chosen node info. prom interface will handle errors.
	 */
	dnode = prom_chosennode();

	/*
	 * Look for the "iosram" property on the chosen node with a prom
	 * interface as ddi_find_devinfo() couldn't be used (calls
	 * ddi_walk_devs() that creates one extra lock on the device tree).
	 */
	if (prom_getprop(dnode, IOSRAM_CHOSEN_PROP, (caddr_t)&nodeid) <= 0) {
		/*
		 * No I/O Board SBBC set up as console, what to do ?
		 */
		SBBC_ERR(CE_PANIC, "No SBBC found for Console/TOD \n");
	}

	if (prom_getprop(dnode, IOSRAM_TOC_PROP,
	    (caddr_t)&softsp->sram_toc) <= 0) {
		/*
		 * SRAM TOC Offset defaults to 0
		 */
		SBBC_ERR(CE_WARN, "No SBBC TOC Offset found\n");
		softsp->sram_toc = 0;
	}

	/*
	 * get the full OBP pathname of this node
	 */
	if (prom_phandle_to_path((phandle_t)nodeid, master_sbbc,
		sizeof (master_sbbc)) < 0) {

		SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
		    nodeid);
	}
	SGSBBC_DBG_ALL("chosen pathname : %s\n", master_sbbc);
	SGSBBC_DBG_ALL("device pathname : %s\n", ddi_pathname(softsp->dip, pn));
	if (strcmp(master_sbbc, ddi_pathname(softsp->dip, pn)) == 0) {

		/*
		 * map in the SBBC regs
		 */

		if (sbbc_map_regs(softsp) != DDI_SUCCESS) {
			SBBC_ERR(CE_PANIC, "Can't map the SBBC regs \n");
		}
		/*
		 * Only the 'chosen' node is used for iosram_read()/_write()
		 * Must initialise the tunnel before the console/tod
		 *
		 */
		if (iosram_tunnel_init(softsp) == DDI_FAILURE) {
			SBBC_ERR(CE_PANIC, "Can't create the SRAM <-> SC "
				"comm. tunnel \n");
		}

		master_chosen = TRUE;

		/*
		 * Verify that an 'interrupts' property
		 * exists for this device
		 */

		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
			DDI_PROP_DONTPASS, "interrupts",
			&len) != DDI_PROP_SUCCESS) {

			SBBC_ERR(CE_PANIC, "No 'interrupts' property for the "
					"'chosen' SBBC \n");
		}

		/*
		 * add the interrupt handler
		 * NB
		 * should this be a high-level interrupt ?
		 * NB
		 */
		if (sbbc_add_intr(softsp) == DDI_FAILURE) {
			SBBC_ERR(CE_PANIC, "Can't add interrupt handler for "
					"'chosen' SBBC \n");
		}

		sbbc_enable_intr(softsp);

		/*
		 * Create the mailbox
		 */
		if (sbbc_mbox_create(softsp) != 0) {
			cmn_err(CE_WARN, "No IOSRAM MailBox created!\n");
		}

	}
}
Example #5
0
static int
sbbc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int			instance;
	sbbc_softstate_t	*softsp;
	uint32_t		*pci_intr_enable_reg;
	int			len;
#ifdef	DEBUG
	char			name[8];
#endif	/* DEBUG */

	instance = ddi_get_instance(devi);

	switch (cmd) {
	case DDI_ATTACH:

		if (ddi_soft_state_zalloc(sbbcp, instance) != 0)
			return (DDI_FAILURE);

		softsp = ddi_get_soft_state(sbbcp, instance);
		softsp->sbbc_instance = instance;

		/*
		 * Set the dip in the soft state
		 * And get interrupt cookies and initialize the
		 * per instance mutex.
		 */
		softsp_init(softsp, devi);


		/*
		 * Verify that an 'interrupts' property exists for
		 * this device. If not, this instance will be ignored.
		 */
		if (ddi_getproplen(DDI_DEV_T_ANY, softsp->dip,
			DDI_PROP_DONTPASS, "interrupts",
			&len) != DDI_PROP_SUCCESS) {
			SBBC_ERR1(CE_WARN, "No 'interrupts' property for the "
					"SBBC instance %d\n", instance);
			return (DDI_FAILURE);
		}
		/*
		 * Add this instance to the sbbc chosen iosram list
		 * so that it can be used for tunnel switch.
		 */
		mutex_enter(&chosen_lock);
		softsp->sbbc_state = SBBC_STATE_INIT;
		sbbc_add_instance(softsp);

		/*
		 * If this is the chosen IOSRAM and there is no master IOSRAM
		 * yet, then let's set this instance as the master.
		 * if there is a master alreay due to the previous tunnel switch
		 * then keep as is even though this is the chosen.
		 */
		if (sgsbbc_iosram_is_chosen(softsp)) {
			ASSERT(master_iosram);
			softsp->iosram = master_iosram;
			master_iosram->sgsbbc = softsp;

			/* Do 'chosen' init only */
			sbbc_chosen_init(softsp);
		}

		mutex_exit(&chosen_lock);
#ifdef	DEBUG
		(void) sprintf(name, "sbbc%d", instance);

		if (ddi_create_minor_node(devi, name, S_IFCHR, instance,
			NULL, NULL) == DDI_FAILURE) {
			mutex_destroy(&softsp->sbbc_lock);
			ddi_remove_minor_node(devi, NULL);
			ddi_soft_state_free(sbbcp, instance);
			return (DDI_FAILURE);
		}
#endif	/* DEBUG */

		ddi_report_dev(devi);

		return (DDI_SUCCESS);

	case DDI_RESUME:

		if (!(softsp = ddi_get_soft_state(sbbcp, instance)))
			return (DDI_FAILURE);

		mutex_enter(&softsp->sbbc_lock);
		if ((softsp->suspended == TRUE) && (softsp->chosen == TRUE)) {
			/*
			 * Enable Interrupts now, turn on both INT#A lines
			 */
			pci_intr_enable_reg =  (uint32_t *)
					((char *)softsp->sbbc_regs +
						SBBC_PCI_INT_ENABLE);

			ddi_put32(softsp->sbbc_reg_handle1,
				pci_intr_enable_reg,
				(uint32_t)SBBC_PCI_ENABLE_INT_A);

			/*
			 * Reset intr_in_enabled to the original value
			 * so the SC can send us interrupt.
			 */
			if (iosram_write(SBBC_SC_INTR_ENABLED_KEY,
				0, (caddr_t)&intr_in_enabled,
				sizeof (intr_in_enabled))) {

				mutex_exit(&softsp->sbbc_lock);
				return (DDI_FAILURE);
			}
		}
		softsp->suspended = FALSE;

		mutex_exit(&softsp->sbbc_lock);

		return (DDI_SUCCESS);

	default:
		return (DDI_FAILURE);
	}
}