diff options
Diffstat (limited to 'usr/src/uts/common/io')
| -rw-r--r-- | usr/src/uts/common/io/asy.c | 871 | ||||
| -rw-r--r-- | usr/src/uts/common/io/audio/sada/drv/audio810/audio810.c | 258 | ||||
| -rw-r--r-- | usr/src/uts/common/io/fdc.c | 111 | ||||
| -rw-r--r-- | usr/src/uts/common/io/i8042.c | 72 | ||||
| -rw-r--r-- | usr/src/uts/common/io/kb8042/kb8042.c | 90 | ||||
| -rw-r--r-- | usr/src/uts/common/io/kb8042/kb8042.h | 12 | ||||
| -rw-r--r-- | usr/src/uts/common/io/pci-ide/pci-ide.c | 74 | ||||
| -rw-r--r-- | usr/src/uts/common/io/pm.c | 359 | ||||
| -rw-r--r-- | usr/src/uts/common/io/ppm/ppm.c | 175 | ||||
| -rw-r--r-- | usr/src/uts/common/io/ppm/ppm_subr.c | 74 | ||||
| -rw-r--r-- | usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c | 59 | ||||
| -rwxr-xr-x | usr/src/uts/common/io/srn.c | 563 | ||||
| -rwxr-xr-x | usr/src/uts/common/io/srn.conf | 27 | ||||
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/ehci/ehci.c | 7 | ||||
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c | 3 | ||||
| -rw-r--r-- | usr/src/uts/common/io/usb/hcd/openhci/ohci.c | 4 | 
16 files changed, 2264 insertions, 495 deletions
| diff --git a/usr/src/uts/common/io/asy.c b/usr/src/uts/common/io/asy.c index 1062cd28f8..12ff96c905 100644 --- a/usr/src/uts/common/io/asy.c +++ b/usr/src/uts/common/io/asy.c @@ -230,6 +230,15 @@ static const int standard_com_ports[] = {  static int *com_ports;  static uint_t num_com_ports; +#ifdef	DEBUG +/* + * Set this to true to make the driver pretend to do a suspend.  Useful + * for debugging suspend/resume code with a serial debugger. + */ +boolean_t	asy_nosuspend = B_FALSE; +#endif + +  /*   * Baud rate table. Indexed by #defines found in sys/termios.h   */ @@ -272,6 +281,7 @@ ushort_t asyspdtab[] = {  static int asyrsrv(queue_t *q);  static int asyopen(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);  static int asyclose(queue_t *q, int flag, cred_t *credp); +static int asywputdo(queue_t *q, mblk_t *mp, boolean_t);  static int asywput(queue_t *q, mblk_t *mp);  struct module_info asy_info = { @@ -392,7 +402,7 @@ _fini(void)  		asy_addedsoft = 0;  		/* free "motherboard-serial-ports" property if allocated */  		if (com_ports != NULL && com_ports != (int *)standard_com_ports) -		    ddi_prop_free(com_ports); +			ddi_prop_free(com_ports);  		com_ports = NULL;  		mutex_destroy(&asy_soft_lock);  		ddi_soft_state_fini(&asy_soft_state); @@ -406,6 +416,59 @@ _info(struct modinfo *modinfop)  	return (mod_info(&modlinkage, modinfop));  } +void +async_put_suspq(struct asycom *asy, mblk_t *mp) +{ +	struct asyncline *async = asy->asy_priv; + +	ASSERT(mutex_owned(&asy->asy_excl)); + +	if (async->async_suspqf == NULL) +		async->async_suspqf = mp; +	else +		async->async_suspqb->b_next = mp; + +	async->async_suspqb = mp; +} + +static mblk_t * +async_get_suspq(struct asycom *asy) +{ +	struct asyncline *async = asy->asy_priv; +	mblk_t *mp; + +	ASSERT(mutex_owned(&asy->asy_excl)); + +	if ((mp = async->async_suspqf) != NULL) { +		async->async_suspqf = mp->b_next; +		mp->b_next = NULL; +	} else { +		async->async_suspqb = NULL; +	} +	return (mp); +} + +static void +async_process_suspq(struct asycom *asy) +{ +	struct asyncline *async = asy->asy_priv; +	mblk_t *mp; + +	ASSERT(mutex_owned(&asy->asy_excl)); + +	while ((mp = async_get_suspq(asy)) != NULL) { +		queue_t *q; + +		q = async->async_ttycommon.t_writeq; +		ASSERT(q != NULL); +		mutex_exit(&asy->asy_excl); +		(void) asywputdo(q, mp, B_FALSE); +		mutex_enter(&asy->asy_excl); +	} +	async->async_flags &= ~ASYNC_DDI_SUSPENDED; +	cv_broadcast(&async->async_flags_cv); +} +  static int  asy_get_bus_type(dev_info_t *devinfo)  { @@ -494,7 +557,7 @@ asy_get_io_regnum_isa(dev_info_t *devi, struct asycom *asy)  	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,  	    "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) {  		cmn_err(CE_WARN, "asy_get_io_regnum: reg property not found " -			"in devices property list"); +		    "in devices property list");  		return (-1);  	} @@ -545,9 +608,6 @@ asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd)  	struct asycom *asy;  	struct asyncline *async; -	if (cmd != DDI_DETACH) -		return (DDI_FAILURE); -  	instance = ddi_get_instance(devi);	/* find out which unit */  	asy = ddi_get_soft_state(asy_soft_state, instance); @@ -555,25 +615,104 @@ asydetach(dev_info_t *devi, ddi_detach_cmd_t cmd)  		return (DDI_FAILURE);  	async = asy->asy_priv; -	DEBUGNOTE2(ASY_DEBUG_INIT, "asy%d: %s shutdown.", -	    instance, asy_hw_name(asy)); +	switch (cmd) { +	case DDI_DETACH: +		DEBUGNOTE2(ASY_DEBUG_INIT, "asy%d: %s shutdown.", +		    instance, asy_hw_name(asy)); -	/* cancel DTR hold timeout */ -	if (async->async_dtrtid != 0) { -		(void) untimeout(async->async_dtrtid); -		async->async_dtrtid = 0; -	} +		/* cancel DTR hold timeout */ +		if (async->async_dtrtid != 0) { +			(void) untimeout(async->async_dtrtid); +			async->async_dtrtid = 0; +		} + +		/* remove all minor device node(s) for this device */ +		ddi_remove_minor_node(devi, NULL); + +		mutex_destroy(&asy->asy_excl); +		mutex_destroy(&asy->asy_excl_hi); +		cv_destroy(&async->async_flags_cv); +		ddi_remove_intr(devi, 0, asy->asy_iblock); +		ddi_regs_map_free(&asy->asy_iohandle); +		asy_soft_state_free(asy); +		DEBUGNOTE1(ASY_DEBUG_INIT, "asy%d: shutdown complete", +		    instance); +		break; +	case DDI_SUSPEND: +		{ +		unsigned i; +		uchar_t lsr; + +#ifdef	DEBUG +		if (asy_nosuspend) +			return (DDI_SUCCESS); +#endif +		mutex_enter(&asy->asy_excl); + +		ASSERT(async->async_ops >= 0); +		while (async->async_ops > 0) +			cv_wait(&async->async_ops_cv, &asy->asy_excl); + +		async->async_flags |= ASYNC_DDI_SUSPENDED; + +		/* Wait for timed break and delay to complete */ +		while ((async->async_flags & (ASYNC_BREAK|ASYNC_DELAY))) { +			if (cv_wait_sig(&async->async_flags_cv, &asy->asy_excl) +			    == 0) { +				async_process_suspq(asy); +				mutex_exit(&asy->asy_excl); +				return (DDI_FAILURE); +			} +		} + +		/* Clear untimed break */ +		if (async->async_flags & ASYNC_OUT_SUSPEND) +			async_resume_utbrk(async); + +		mutex_exit(&asy->asy_excl); + +		mutex_enter(&asy->asy_soft_sr); +		mutex_enter(&asy->asy_excl); +		if (async->async_wbufcid != 0) { +			bufcall_id_t bcid = async->async_wbufcid; +			async->async_wbufcid = 0; +			async->async_flags |= ASYNC_RESUME_BUFCALL; +			mutex_exit(&asy->asy_excl); +			unbufcall(bcid); +			mutex_enter(&asy->asy_excl); +		} +		mutex_enter(&asy->asy_excl_hi); -	/* remove all minor device node(s) for this device */ -	ddi_remove_minor_node(devi, NULL); +		/* Disable interrupts from chip */ +		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0); +		asy->asy_flags |= ASY_DDI_SUSPENDED; + +		/* Process remaining RX characters and RX errors, if any */ +		lsr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR); +		async_rxint(asy, lsr); + +		/* Wait for TX to drain */ +		for (i = 1000; i > 0; i--) { +			lsr = ddi_get8(asy->asy_iohandle, +			    asy->asy_ioaddr + LSR); +			if ((lsr & (XSRE | XHRE)) == (XSRE | XHRE)) +				break; +			delay(drv_usectohz(10000)); +		} +		if (i == 0) +			cmn_err(CE_WARN, +			    "asy: transmitter wasn't drained before " +			    "driver was suspended"); + +		mutex_exit(&asy->asy_excl_hi); +		mutex_exit(&asy->asy_excl); +		mutex_exit(&asy->asy_soft_sr); +		break; +	} +	default: +		return (DDI_FAILURE); +	} -	mutex_destroy(&asy->asy_excl); -	mutex_destroy(&asy->asy_excl_hi); -	cv_destroy(&async->async_flags_cv); -	ddi_remove_intr(devi, 0, asy->asy_iblock); -	ddi_regs_map_free(&asy->asy_iohandle); -	asy_soft_state_free(asy); -	DEBUGNOTE1(ASY_DEBUG_INIT, "asy%d: shutdown complete", instance);  	return (DDI_SUCCESS);  } @@ -610,10 +749,73 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  		DDI_STRICTORDER_ACC,  	}; -	if (cmd != DDI_ATTACH) +	instance = ddi_get_instance(devi);	/* find out which unit */ + +	switch (cmd) { +	case DDI_ATTACH: +		break; +	case DDI_RESUME: +	{ +		struct asyncline *async; + +#ifdef	DEBUG +		if (asy_nosuspend) +			return (DDI_SUCCESS); +#endif +		asy = ddi_get_soft_state(asy_soft_state, instance); +		if (asy == NULL) +			return (DDI_FAILURE); + +		mutex_enter(&asy->asy_soft_sr); +		mutex_enter(&asy->asy_excl); +		mutex_enter(&asy->asy_excl_hi); + +		async = asy->asy_priv; +		/* Disable interrupts */ +		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0); +		if (asy_identify_chip(devi, asy) != DDI_SUCCESS) { +			mutex_exit(&asy->asy_excl_hi); +			mutex_exit(&asy->asy_excl); +			mutex_exit(&asy->asy_soft_sr); +			cmn_err(CE_WARN, "Cannot identify UART chip at %p\n", +			    (void *)asy->asy_ioaddr); +			return (DDI_FAILURE); +		} +		asy->asy_flags &= ~ASY_DDI_SUSPENDED; +		if (async->async_flags & ASYNC_ISOPEN) { +			asy_program(asy, ASY_INIT); +			/* Kick off output */ +			if (async->async_ocnt > 0) { +				async_resume(async); +			} else { +				mutex_exit(&asy->asy_excl_hi); +				if (async->async_xmitblk) +					freeb(async->async_xmitblk); +				async->async_xmitblk = NULL; +				async_start(async); +				mutex_enter(&asy->asy_excl_hi); +			} +			ASYSETSOFT(asy); +		} +		mutex_exit(&asy->asy_excl_hi); +		mutex_exit(&asy->asy_excl); +		mutex_exit(&asy->asy_soft_sr); + +		mutex_enter(&asy->asy_excl); +		if (async->async_flags & ASYNC_RESUME_BUFCALL) { +			async->async_wbufcid = bufcall(async->async_wbufcds, +			    BPRI_HI, (void (*)(void *)) async_reioctl, +			    (void *)(intptr_t)async->async_common->asy_unit); +			async->async_flags &= ~ASYNC_RESUME_BUFCALL; +		} +		async_process_suspq(asy); +		mutex_exit(&asy->asy_excl); +		return (DDI_SUCCESS); +	} +	default:  		return (DDI_FAILURE); +	} -	instance = ddi_get_instance(devi);	/* find out which unit */  	ret = ddi_soft_state_zalloc(asy_soft_state, instance);  	if (ret != DDI_SUCCESS)  		return (DDI_FAILURE); @@ -773,7 +975,8 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  	 */  	mutex_init(&asy->asy_excl, NULL, MUTEX_DRIVER, asy_soft_iblock);  	mutex_init(&asy->asy_excl_hi, NULL, MUTEX_DRIVER, -		(void *)asy->asy_iblock); +	    (void *)asy->asy_iblock); +	mutex_init(&asy->asy_soft_sr, NULL, MUTEX_DRIVER, asy_soft_iblock);  	mutex_enter(&asy->asy_excl);  	mutex_enter(&asy->asy_excl_hi); @@ -783,6 +986,7 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  		mutex_exit(&asy->asy_excl);  		mutex_destroy(&asy->asy_excl);  		mutex_destroy(&asy->asy_excl_hi); +		mutex_destroy(&asy->asy_soft_sr);  		ddi_regs_map_free(&asy->asy_iohandle);  		cmn_err(CE_CONT, "Cannot identify UART chip at %p\n",  		    (void *)asy->asy_ioaddr); @@ -796,11 +1000,10 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, DLAB);  	/* Set the baud rate to 9600 */  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + (DAT+DLL), -		asyspdtab[asy->asy_bidx] & 0xff); +	    asyspdtab[asy->asy_bidx] & 0xff);  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + (DAT+DLH), -		(asyspdtab[asy->asy_bidx] >> 8) & 0xff); -	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, -		asy->asy_lcr); +	    (asyspdtab[asy->asy_bidx] >> 8) & 0xff); +	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, asy->asy_lcr);  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, mcr);  	mutex_exit(&asy->asy_excl_hi); @@ -821,12 +1024,12 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  			ddi_regs_map_free(&asy->asy_iohandle);  			mutex_exit(&asy_glob_lock);  			cmn_err(CE_CONT, -				"Can not set soft interrupt for ASY driver\n"); +			    "Can not set soft interrupt for ASY driver\n");  			asy_soft_state_free(asy);  			return (DDI_FAILURE);  		}  		mutex_init(&asy_soft_lock, NULL, MUTEX_DRIVER, -			(void *)asy->asy_iblock); +		    (void *)asy->asy_iblock);  		asy_addedsoft++;  	}  	mutex_exit(&asy_glob_lock); @@ -845,7 +1048,7 @@ asyattach(dev_info_t *devi, ddi_attach_cmd_t cmd)  		mutex_destroy(&asy->asy_excl_hi);  		ddi_regs_map_free(&asy->asy_iohandle);  		cmn_err(CE_CONT, -			"Can not set device interrupt for ASY driver\n"); +		    "Can not set device interrupt for ASY driver\n");  		asy_soft_state_free(asy);  		return (DDI_FAILURE);  	} @@ -959,20 +1162,17 @@ asy_getproperty(dev_info_t *devi, struct asycom *asy, const char *property)  	if (ret != DDI_PROP_SUCCESS) {  		(void) sprintf(name, "com%c-%s", number, property);  		len = sizeof (val); -		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, -				&len); +		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len);  	}  	if (ret != DDI_PROP_SUCCESS) {  		(void) sprintf(name, "tty0%c-%s", number, property);  		len = sizeof (val); -		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, -				&len); +		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len);  	}  	if (ret != DDI_PROP_SUCCESS) {  		(void) sprintf(name, "port-%c-%s", letter, property);  		len = sizeof (val); -		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, -				&len); +		ret = GET_PROP(devi, name, DDI_PROP_CANSLEEP, val, &len);  	}  	if (ret != DDI_PROP_SUCCESS)  		return (-1);		/* property non-existant */ @@ -1375,7 +1575,7 @@ again:  			kmem_free(termiosp, len);  		} else  			cmn_err(CE_WARN, -				"asy: couldn't get ttymodes property!"); +			    "asy: couldn't get ttymodes property!");  		mutex_enter(&asy->asy_excl_hi);  		/* eeprom mode support - respect properties */ @@ -1394,8 +1594,9 @@ again:  		async->async_startc = CSTART;  		async->async_stopc = CSTOP;  		asy_program(asy, ASY_INIT); -	} else if ((async->async_ttycommon.t_flags & TS_XCLUDE) && -						secpolicy_excl_open(cr) != 0) { +	} else +		if ((async->async_ttycommon.t_flags & TS_XCLUDE) && +		    secpolicy_excl_open(cr) != 0) {  		mutex_exit(&asy->asy_excl_hi);  		mutex_exit(&asy->asy_excl);  		return (EBUSY); @@ -1427,17 +1628,18 @@ again:  	mcr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + MCR);  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, -		mcr|(asy->asy_mcr&DTR)); +	    mcr|(asy->asy_mcr&DTR));  	DEBUGCONT3(ASY_DEBUG_INIT, -		"asy%dopen: \"Raise DTR on every open\": make mcr = %x, " -		"make TS_SOFTCAR = %s\n", -		unit, mcr|(asy->asy_mcr&DTR), -		(asy->asy_flags & ASY_IGNORE_CD) ? "ON" : "OFF"); +	    "asy%dopen: \"Raise DTR on every open\": make mcr = %x, " +	    "make TS_SOFTCAR = %s\n", +	    unit, mcr|(asy->asy_mcr&DTR), +	    (asy->asy_flags & ASY_IGNORE_CD) ? "ON" : "OFF"); +  	if (asy->asy_flags & ASY_IGNORE_CD) {  		DEBUGCONT1(ASY_DEBUG_MODEM, -			"asy%dopen: ASY_IGNORE_CD set, set TS_SOFTCAR\n", -			unit); +		    "asy%dopen: ASY_IGNORE_CD set, set TS_SOFTCAR\n", +		    unit);  		async->async_ttycommon.t_flags |= TS_SOFTCAR;  	}  	else @@ -1448,10 +1650,11 @@ again:  	 */  	asy->asy_msr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + MSR);  	DEBUGCONT3(ASY_DEBUG_INIT, "asy%dopen: TS_SOFTCAR is %s, " -		"MSR & DCD is %s\n", -		unit, -		(async->async_ttycommon.t_flags & TS_SOFTCAR) ? "set" : "clear", -		(asy->asy_msr & DCD) ? "set" : "clear"); +	    "MSR & DCD is %s\n", +	    unit, +	    (async->async_ttycommon.t_flags & TS_SOFTCAR) ? "set" : "clear", +	    (asy->asy_msr & DCD) ? "set" : "clear"); +  	if (asy->asy_msr & DCD)  		async->async_flags |= ASYNC_CARR_ON;  	else @@ -1671,33 +1874,34 @@ nodrain:  	 * If line has HUPCL set or is incompletely opened fix up the modem  	 * lines.  	 */ -	DEBUGCONT1(ASY_DEBUG_MODEM, -		"asy%dclose: next check HUPCL flag\n", instance); +	DEBUGCONT1(ASY_DEBUG_MODEM, "asy%dclose: next check HUPCL flag\n", +	    instance);  	mutex_enter(&asy->asy_excl_hi);  	if ((async->async_ttycommon.t_cflag & HUPCL) ||  	    (async->async_flags & ASYNC_WOPEN)) {  		DEBUGCONT3(ASY_DEBUG_MODEM, -			"asy%dclose: HUPCL flag = %x, ASYNC_WOPEN flag = %x\n", -			instance, -			async->async_ttycommon.t_cflag & HUPCL, -			async->async_ttycommon.t_cflag & ASYNC_WOPEN); +		    "asy%dclose: HUPCL flag = %x, ASYNC_WOPEN flag = %x\n", +		    instance, +		    async->async_ttycommon.t_cflag & HUPCL, +		    async->async_ttycommon.t_cflag & ASYNC_WOPEN);  		async->async_flags |= ASYNC_DTR_DELAY;  		/* turn off DTR, RTS but NOT interrupt to 386 */  		if (asy->asy_flags & (ASY_IGNORE_CD|ASY_RTS_DTR_OFF)) {  			DEBUGCONT3(ASY_DEBUG_MODEM, -				"asy%dclose: ASY_IGNORE_CD flag = %x, " -				"ASY_RTS_DTR_OFF flag = %x\n", -				instance, -				asy->asy_flags & ASY_IGNORE_CD, -				asy->asy_flags & ASY_RTS_DTR_OFF); -			ddi_put8(asy->asy_iohandle, -				asy->asy_ioaddr + MCR, asy->asy_mcr|OUT2); +			    "asy%dclose: ASY_IGNORE_CD flag = %x, " +			    "ASY_RTS_DTR_OFF flag = %x\n", +			    instance, +			    asy->asy_flags & ASY_IGNORE_CD, +			    asy->asy_flags & ASY_RTS_DTR_OFF); + +			ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, +			    asy->asy_mcr|OUT2);  		} else {  			DEBUGCONT1(ASY_DEBUG_MODEM,  			    "asy%dclose: Dropping DTR and RTS\n", instance); -			ddi_put8(asy->asy_iohandle, -				asy->asy_ioaddr + MCR, OUT2); +			ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, +			    OUT2);  		}  		async->async_dtrtid =  		    timeout((void (*)())async_dtr_free, @@ -1707,10 +1911,9 @@ nodrain:  	 * If nobody's using it now, turn off receiver interrupts.  	 */  	if ((async->async_flags & (ASYNC_WOPEN|ASYNC_ISOPEN)) == 0) { -		icr = ddi_get8(asy->asy_iohandle, -			asy->asy_ioaddr + ICR); +		icr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + ICR);  		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, -			(icr & ~RIEN)); +		    (icr & ~RIEN));  	}  	mutex_exit(&asy->asy_excl_hi);  out: @@ -1750,9 +1953,12 @@ asy_isbusy(struct asycom *asy)  	async = asy->asy_priv;  	ASSERT(mutex_owned(&asy->asy_excl));  	ASSERT(mutex_owned(&asy->asy_excl_hi)); +/* + * XXXX this should be recoded + */  	return ((async->async_ocnt > 0) || -		((ddi_get8(asy->asy_iohandle, -		    asy->asy_ioaddr + LSR) & (XSRE|XHRE)) == 0)); +	    ((ddi_get8(asy->asy_iohandle, +	    asy->asy_ioaddr + LSR) & (XSRE|XHRE)) == 0));  }  static void @@ -1826,7 +2032,7 @@ asy_program(struct asycom *asy, int mode)  #ifdef DEBUG  	instance = UNIT(async->async_dev);  	DEBUGCONT2(ASY_DEBUG_PROCS, -		"asy%d_program: mode = 0x%08X, enter\n", instance, mode); +	    "asy%d_program: mode = 0x%08X, enter\n", instance, mode);  #endif  	baudrate = BAUDINDEX(async->async_ttycommon.t_cflag); @@ -1836,15 +2042,15 @@ asy_program(struct asycom *asy, int mode)  	if (baudrate > CBAUD) {  		async->async_ttycommon.t_cflag |= CIBAUDEXT;  		async->async_ttycommon.t_cflag |= -			(((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD); +		    (((baudrate - CBAUD - 1) << IBSHIFT) & CIBAUD);  	} else {  		async->async_ttycommon.t_cflag &= ~CIBAUDEXT;  		async->async_ttycommon.t_cflag |= -			((baudrate << IBSHIFT) & CIBAUD); +		    ((baudrate << IBSHIFT) & CIBAUD);  	}  	c_flag = async->async_ttycommon.t_cflag & -		(CLOCAL|CREAD|CSTOPB|CSIZE|PARENB|PARODD|CBAUD|CBAUDEXT); +	    (CLOCAL|CREAD|CSTOPB|CSIZE|PARENB|PARODD|CBAUD|CBAUDEXT);  	/* disable interrupts */  	ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, 0); @@ -1855,7 +2061,7 @@ asy_program(struct asycom *asy, int mode)  	(void) ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + ISR);  	(void) ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR);  	asy->asy_msr = flush_reg = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + MSR); +	    asy->asy_ioaddr + MSR);  	/*  	 * The device is programmed in the open sequence, if we  	 * have to hardware handshake, then this is a good time @@ -1892,17 +2098,16 @@ asy_program(struct asycom *asy, int mode)  		if (asy->asy_use_fifo == FIFO_ON) {  			for (flush_reg = asy->asy_fifo_buf; flush_reg-- > 0; ) {  				(void) ddi_get8(asy->asy_iohandle, -						asy->asy_ioaddr + DAT); +				    asy->asy_ioaddr + DAT);  			}  		} else {  			flush_reg = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + DAT); +			    asy->asy_ioaddr + DAT);  		}  	if (ocflags != (c_flag & ~CLOCAL) || mode == ASY_INIT) {  		/* Set line control */ -		lcr = ddi_get8(asy->asy_iohandle, -			asy->asy_ioaddr + LCR); +		lcr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LCR);  		lcr &= ~(WLS0|WLS1|STB|PEN|EPS);  		if (c_flag & CSTOPB) @@ -1930,13 +2135,13 @@ asy_program(struct asycom *asy, int mode)  		}  		/* set the baud rate, unless it is "0" */ -		ddi_put8(asy->asy_iohandle, -			asy->asy_ioaddr + LCR, DLAB); +		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, DLAB); +  		if (baudrate != 0) {  			ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + DAT, -				asyspdtab[baudrate] & 0xff); +			    asyspdtab[baudrate] & 0xff);  			ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + ICR, -				(asyspdtab[baudrate] >> 8) & 0xff); +			    (asyspdtab[baudrate] >> 8) & 0xff);  		}  		/* set the line control modes */  		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, lcr); @@ -1957,10 +2162,10 @@ asy_program(struct asycom *asy, int mode)  	if (baudrate == 0)  		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, -			(asy->asy_mcr & RTS) | OUT2); +		    (asy->asy_mcr & RTS) | OUT2);  	else  		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + MCR, -			asy->asy_mcr | OUT2); +		    asy->asy_mcr | OUT2);  	/*  	 * Call the modem status interrupt handler to check for the carrier @@ -1971,10 +2176,10 @@ asy_program(struct asycom *asy, int mode)  	/* Set interrupt control */  	DEBUGCONT3(ASY_DEBUG_MODM2, -		"asy%d_program: c_flag & CLOCAL = %x t_cflag & CRTSCTS = %x\n", -		instance, -		c_flag & CLOCAL, -		async->async_ttycommon.t_cflag & CRTSCTS); +	    "asy%d_program: c_flag & CLOCAL = %x t_cflag & CRTSCTS = %x\n", +	    instance, c_flag & CLOCAL, +	    async->async_ttycommon.t_cflag & CRTSCTS); +  	if ((c_flag & CLOCAL) && !(async->async_ttycommon.t_cflag & CRTSCTS))  		/*  		 * direct-wired line ignores DCD, so we don't enable modem @@ -2026,10 +2231,11 @@ asyintr(caddr_t argasy)  	uchar_t			interrupt_id, lsr;  	interrupt_id = ddi_get8(asy->asy_iohandle, -				asy->asy_ioaddr + ISR) & 0x0F; +	    asy->asy_ioaddr + ISR) & 0x0F;  	async = asy->asy_priv; +  	if ((async == NULL) || asy_addedsoft == 0 || -		!(async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN))) { +	    !(async->async_flags & (ASYNC_ISOPEN|ASYNC_WOPEN))) {  		if (interrupt_id & NOINTERRUPT)  			return (DDI_INTR_UNCLAIMED);  		else { @@ -2040,30 +2246,31 @@ asyintr(caddr_t argasy)  			 *	reading modem status  			 */  			(void) ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + LSR); +			    asy->asy_ioaddr + LSR);  			(void) ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + DAT); +			    asy->asy_ioaddr + DAT);  			asy->asy_msr = ddi_get8(asy->asy_iohandle, -						asy->asy_ioaddr + MSR); +			    asy->asy_ioaddr + MSR);  			return (DDI_INTR_CLAIMED);  		}  	} +  	mutex_enter(&asy->asy_excl_hi);  	/*  	 * We will loop until the interrupt line is pulled low. asy  	 * interrupt is edge triggered.  	 */  	/* CSTYLED */ -	for (;; interrupt_id = (ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + ISR) & 0x0F)) { +	for (;; interrupt_id = +	    (ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + ISR) & 0x0F)) { +  		if (interrupt_id & NOINTERRUPT)  			break;  		ret_status = DDI_INTR_CLAIMED; -		DEBUGCONT1(ASY_DEBUG_INTR, -			"asyintr: interrupt_id = 0x%d\n", interrupt_id); -		lsr = ddi_get8(asy->asy_iohandle, -			asy->asy_ioaddr + LSR); +		DEBUGCONT1(ASY_DEBUG_INTR, "asyintr: interrupt_id = 0x%d\n", +		    interrupt_id); +		lsr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR);  		switch (interrupt_id) {  		case RxRDY:  		case RSTATUS: @@ -2218,9 +2425,9 @@ async_rxint(struct asycom *asy, uchar_t lsr)  	if (!(tp->t_cflag & CREAD)) {  		while (lsr & (RCA|PARERR|FRMERR|BRKDET|OVRRUN)) {  			(void) (ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + DAT) & 0xff); +			    asy->asy_ioaddr + DAT) & 0xff);  			lsr = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + LSR); +			    asy->asy_ioaddr + LSR);  			if (looplim-- < 0)		/* limit loop */  				break;  		} @@ -2232,7 +2439,7 @@ async_rxint(struct asycom *asy, uchar_t lsr)  		s = 0;				/* reset error status */  		if (lsr & RCA) {  			c = ddi_get8(asy->asy_iohandle, -				asy->asy_ioaddr + DAT) & 0xff; +			    asy->asy_ioaddr + DAT) & 0xff;  			/*  			 * We handle XON/XOFF char if IXON is set, @@ -2319,8 +2526,7 @@ async_rxint(struct asycom *asy, uchar_t lsr)  				else  					async->async_sw_overrun = 1;  check_looplim: -		lsr = ddi_get8(asy->asy_iohandle, -			asy->asy_ioaddr + LSR); +		lsr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR);  		if (looplim-- < 0)		/* limit loop */  			break;  	} @@ -2355,19 +2561,19 @@ async_msint_retry:  	/* this resets the interrupt */  	msr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + MSR);  	DEBUGCONT10(ASY_DEBUG_STATE, -		"async%d_msint call #%d:\n" -		"   transition: %3s %3s %3s %3s\n" -		"current state: %3s %3s %3s %3s\n", -		instance, -		++(asy->asy_msint_cnt), -		(msr & DCTS) ? "DCTS" : "    ", -		(msr & DDSR) ? "DDSR" : "    ", -		(msr & DRI)  ? "DRI " : "    ", -		(msr & DDCD) ? "DDCD" : "    ", -		(msr & CTS)  ? "CTS " : "    ", -		(msr & DSR)  ? "DSR " : "    ", -		(msr & RI)   ? "RI  " : "    ", -		(msr & DCD)  ? "DCD " : "    "); +	    "async%d_msint call #%d:\n" +	    "   transition: %3s %3s %3s %3s\n" +	    "current state: %3s %3s %3s %3s\n", +	    instance, +	    ++(asy->asy_msint_cnt), +	    (msr & DCTS) ? "DCTS" : "    ", +	    (msr & DDSR) ? "DDSR" : "    ", +	    (msr & DRI)  ? "DRI " : "    ", +	    (msr & DDCD) ? "DDCD" : "    ", +	    (msr & CTS)  ? "CTS " : "    ", +	    (msr & DSR)  ? "DSR " : "    ", +	    (msr & RI)   ? "RI  " : "    ", +	    (msr & DCD)  ? "DCD " : "    ");  	/* If CTS status is changed, do H/W output flow control */  	if ((t_cflag & CRTSCTS) && (((asy->asy_msr ^ msr) & CTS) != 0)) @@ -2489,17 +2695,16 @@ begin:  		async->async_ext = 0;  		/* check for carrier up */  		DEBUGCONT3(ASY_DEBUG_MODM2, -			"async%d_softint: asy_msr & DCD = %x, " -			"tp->t_flags & TS_SOFTCAR = %x\n", -			instance, -			asy->asy_msr & DCD, -			tp->t_flags & TS_SOFTCAR); +		    "async%d_softint: asy_msr & DCD = %x, " +		    "tp->t_flags & TS_SOFTCAR = %x\n", +		    instance, asy->asy_msr & DCD, tp->t_flags & TS_SOFTCAR); +  		if (asy->asy_msr & DCD) {  			/* carrier present */  			if ((async->async_flags & ASYNC_CARR_ON) == 0) {  				DEBUGCONT1(ASY_DEBUG_MODM2, -					"async%d_softint: set ASYNC_CARR_ON\n", -					instance); +				    "async%d_softint: set ASYNC_CARR_ON\n", +				    instance);  				async->async_flags |= ASYNC_CARR_ON;  				if (async->async_flags & ASYNC_ISOPEN) {  					mutex_exit(&asy->asy_excl_hi); @@ -2517,9 +2722,9 @@ begin:  				int flushflag;  				DEBUGCONT1(ASY_DEBUG_MODEM, -					"async%d_softint: carrier dropped, " -					"so drop DTR\n", -					instance); +				    "async%d_softint: carrier dropped, " +				    "so drop DTR\n", +				    instance);  				/*  				 * Carrier went away.  				 * Drop DTR, abort any output in @@ -2528,60 +2733,62 @@ begin:  				 * notification upstream.  				 */  				val = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + MCR); +				    asy->asy_ioaddr + MCR);  				ddi_put8(asy->asy_iohandle,  				    asy->asy_ioaddr + MCR, (val & ~DTR)); +  				if (async->async_flags & ASYNC_BUSY) { -				    DEBUGCONT0(ASY_DEBUG_BUSY, +					DEBUGCONT0(ASY_DEBUG_BUSY,  					    "async_softint: "  					    "Carrier dropped.  "  					    "Clearing async_ocnt\n"); -				    async->async_ocnt = 0; +					async->async_ocnt = 0;  				}	/* if */  				async->async_flags &= ~ASYNC_STOPPED;  				if (async->async_flags & ASYNC_ISOPEN) { -				    mutex_exit(&asy->asy_excl_hi); -				    mutex_exit(&asy->asy_excl); -				    (void) putctl(q, M_HANGUP); -				    mutex_enter(&asy->asy_excl); -				DEBUGCONT1(ASY_DEBUG_MODEM, -					"async%d_softint: " -					"putctl(q, M_HANGUP)\n", -					instance); -				/* -				 * Flush FIFO buffers -				 * Any data left in there is invalid now -				 */ -				if (asy->asy_use_fifo == FIFO_ON) -					asy_reset_fifo(asy, FIFOTXFLSH); -				/* -				 * Flush our write queue if we have one. -				 * -				 * If we're in the midst of close, then flush -				 * everything.  Don't leave stale ioctls lying -				 * about. -				 */ -				flushflag = (async->async_flags & -				    ASYNC_CLOSING) ? FLUSHALL : FLUSHDATA; -				flushq(tp->t_writeq, flushflag); - -				bp = async->async_xmitblk; /* active msg */ -				if (bp != NULL) { -					freeb(bp); -					async->async_xmitblk = NULL; -				} +					mutex_exit(&asy->asy_excl_hi); +					mutex_exit(&asy->asy_excl); +					(void) putctl(q, M_HANGUP); +					mutex_enter(&asy->asy_excl); +					DEBUGCONT1(ASY_DEBUG_MODEM, +					    "async%d_softint: " +					    "putctl(q, M_HANGUP)\n", +					    instance); +					/* +					 * Flush FIFO buffers +					 * Any data left in there is invalid now +					 */ +					if (asy->asy_use_fifo == FIFO_ON) +						asy_reset_fifo(asy, FIFOTXFLSH); +					/* +					 * Flush our write queue if we have one. +					 * If we're in the midst of close, then +					 * flush everything. Don't leave stale +					 * ioctls lying about. +					 */ +					flushflag = (async->async_flags & +					    ASYNC_CLOSING) ? FLUSHALL : +					    FLUSHDATA; +					flushq(tp->t_writeq, flushflag); + +					/* active msg */ +					bp = async->async_xmitblk; +					if (bp != NULL) { +						freeb(bp); +						async->async_xmitblk = NULL; +					} -				mutex_enter(&asy->asy_excl_hi); -				async->async_flags &= ~ASYNC_BUSY; -				/* -				 * This message warns of Carrier loss -				 * with data left to transmit can hang the -				 * system. -				 */ -				DEBUGCONT0(ASY_DEBUG_MODEM, -					"async_softint: Flushing to " -					"prevent HUPCL hanging\n"); +					mutex_enter(&asy->asy_excl_hi); +					async->async_flags &= ~ASYNC_BUSY; +					/* +					 * This message warns of Carrier loss +					 * with data left to transmit can hang +					 * the system. +					 */ +					DEBUGCONT0(ASY_DEBUG_MODEM, +					    "async_softint: Flushing to " +					    "prevent HUPCL hanging\n");  				}	/* if (ASYNC_ISOPEN) */  			}	/* if (ASYNC_CARR_ON && CLOCAL) */  			async->async_flags &= ~ASYNC_CARR_ON; @@ -2625,8 +2832,10 @@ begin:  		    IN_FLOW_STREAMS);  		mutex_exit(&asy->asy_excl_hi);  	} -	DEBUGCONT2(ASY_DEBUG_INPUT, -		"async%d_softint: %d char(s) in queue.\n", instance, cc); + +	DEBUGCONT2(ASY_DEBUG_INPUT, "async%d_softint: %d char(s) in queue.\n", +	    instance, cc); +  	if (!(bp = allocb(cc, BPRI_MED))) {  		mutex_exit(&asy->asy_excl);  		ttycommon_qfull(&async->async_ttycommon, q); @@ -2648,7 +2857,7 @@ begin:  	if (bp->b_wptr > bp->b_rptr) {  			if (!canput(q)) {  				asyerror(CE_NOTE, "asy%d: local queue full", -					instance); +				    instance);  				freemsg(bp);  			} else  				(void) putq(q, bp); @@ -2732,7 +2941,7 @@ rv:  			mutex_exit(&asy->asy_excl_hi);  			mutex_exit(&asy->asy_excl);  			asyerror(CE_NOTE, "asy%d: ring buffer overflow", -				instance); +			    instance);  			mutex_enter(&asy->asy_excl);  			mutex_enter(&asy->asy_excl_hi);  		} @@ -2775,10 +2984,9 @@ async_restart(void *arg)  	if ((async->async_flags & ASYNC_BREAK) &&  	    !(async->async_flags & ASYNC_OUT_SUSPEND)) {  		mutex_enter(&asy->asy_excl_hi); -		lcr = ddi_get8(asy->asy_iohandle, -			asy->asy_ioaddr + LCR); +		lcr = ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LCR);  		ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, -			(lcr & ~SETBREAK)); +		    (lcr & ~SETBREAK));  		mutex_exit(&asy->asy_excl_hi);  	}  	async->async_flags &= ~(ASYNC_DELAY|ASYNC_BREAK); @@ -2831,9 +3039,9 @@ async_nstart(struct asyncline *async, int mode)  	 */  	if (async->async_flags & (ASYNC_BREAK|ASYNC_BUSY)) {  		DEBUGCONT2((mode? ASY_DEBUG_OUT : 0), -			"async%d_nstart: start %s.\n", -			instance, -			async->async_flags & ASYNC_BREAK ? "break" : "busy"); +		    "async%d_nstart: start %s.\n", +		    instance, +		    async->async_flags & ASYNC_BREAK ? "break" : "busy");  		return;  	} @@ -2851,13 +3059,13 @@ async_nstart(struct asyncline *async, int mode)  	 */  	if (async->async_flags & ASYNC_DELAY) {  		DEBUGCONT1((mode? ASY_DEBUG_OUT : 0), -			"async%d_nstart: start ASYNC_DELAY.\n", instance); +		    "async%d_nstart: start ASYNC_DELAY.\n", instance);  		return;  	}  	if ((q = async->async_ttycommon.t_writeq) == NULL) {  		DEBUGCONT1((mode? ASY_DEBUG_OUT : 0), -			"async%d_nstart: start writeq is null.\n", instance); +		    "async%d_nstart: start writeq is null.\n", instance);  		return;	/* not attached to a stream */  	} @@ -2882,9 +3090,9 @@ async_nstart(struct asyncline *async, int mode)  			 */  			mutex_enter(&asy->asy_excl_hi);  			val = ddi_get8(asy->asy_iohandle, -				asy->asy_ioaddr + LCR); -			ddi_put8(asy->asy_iohandle, -				asy->asy_ioaddr + LCR, (val | SETBREAK)); +			    asy->asy_ioaddr + LCR); +			ddi_put8(asy->asy_iohandle, asy->asy_ioaddr + LCR, +			    (val | SETBREAK));  			mutex_exit(&asy->asy_excl_hi);  			async->async_flags |= ASYNC_BREAK;  			(void) timeout(async_restart, (caddr_t)async, @@ -2977,9 +3185,8 @@ async_nstart(struct asyncline *async, int mode)  	if (didsome)  		async->async_flags |= ASYNC_PROGRESS;  	DEBUGCONT2(ASY_DEBUG_BUSY, -		"async%d_nstart: Set ASYNC_BUSY.  async_ocnt=%d\n", -		instance, -		async->async_ocnt); +	    "async%d_nstart: Set ASYNC_BUSY.  async_ocnt=%d\n", +	    instance, async->async_ocnt);  	async->async_flags |= ASYNC_BUSY;  	mutex_exit(&asy->asy_excl_hi);  } @@ -3123,12 +3330,13 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  	 * ioctls, so keep the others safe too.  	 */  	DEBUGCONT2(ASY_DEBUG_IOCTL, "async%d_ioctl: %s\n", -		instance, -		iocp->ioc_cmd == TIOCMGET ? "TIOCMGET" : -		iocp->ioc_cmd == TIOCMSET ? "TIOCMSET" : -		iocp->ioc_cmd == TIOCMBIS ? "TIOCMBIS" : -		iocp->ioc_cmd == TIOCMBIC ? "TIOCMBIC" : -					    "other"); +	    instance, +	    iocp->ioc_cmd == TIOCMGET ? "TIOCMGET" : +	    iocp->ioc_cmd == TIOCMSET ? "TIOCMSET" : +	    iocp->ioc_cmd == TIOCMBIS ? "TIOCMBIS" : +	    iocp->ioc_cmd == TIOCMBIC ? "TIOCMBIC" : +	    "other"); +  	switch (iocp->ioc_cmd) {  	case TIOCMGET:  	case TIOCGPPS: @@ -3330,14 +3538,15 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  				 * clock / (baud * 16) * 16 * 2.  				 */  				index = BAUDINDEX( -					async->async_ttycommon.t_cflag); +				    async->async_ttycommon.t_cflag);  				async->async_flags |= ASYNC_BREAK; +  				while ((ddi_get8(asy->asy_iohandle,  				    asy->asy_ioaddr + LSR) & XSRE) == 0) {  					mutex_exit(&asy->asy_excl_hi);  					mutex_exit(&asy->asy_excl);  					drv_usecwait( -						32*asyspdtab[index] & 0xfff); +					    32*asyspdtab[index] & 0xfff);  					mutex_enter(&asy->asy_excl);  					mutex_enter(&asy->asy_excl_hi);  				} @@ -3348,23 +3557,23 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  				 * "async_start" to grab the next message.  				 */  				val = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + LCR); +				    asy->asy_ioaddr + LCR);  				ddi_put8(asy->asy_iohandle, -					asy->asy_ioaddr + LCR, -					(val | SETBREAK)); +				    asy->asy_ioaddr + LCR, +				    (val | SETBREAK));  				mutex_exit(&asy->asy_excl_hi);  				(void) timeout(async_restart, (caddr_t)async,  				    drv_usectohz(1000000)/4);  			} else {  				DEBUGCONT1(ASY_DEBUG_OUT, -					"async%d_ioctl: wait for flush.\n", -					instance); +				    "async%d_ioctl: wait for flush.\n", +				    instance);  				mutex_enter(&asy->asy_excl_hi);  				asy_waiteot(asy);  				mutex_exit(&asy->asy_excl_hi);  				DEBUGCONT1(ASY_DEBUG_OUT, -					"async%d_ioctl: ldterm satisfied.\n", -					instance); +				    "async%d_ioctl: ldterm satisfied.\n", +				    instance);  			}  			break; @@ -3409,7 +3618,7 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  		case TIOCMBIC:  			if (iocp->ioc_count != TRANSPARENT) {  				DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " -					"non-transparent\n", instance); +				    "non-transparent\n", instance);  				error = miocpullup(mp, sizeof (int));  				if (error != 0) @@ -3417,14 +3626,14 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  				mutex_enter(&asy->asy_excl_hi);  				(void) asymctl(asy, -					dmtoasy(*(int *)mp->b_cont->b_rptr), -					iocp->ioc_cmd); +				    dmtoasy(*(int *)mp->b_cont->b_rptr), +				    iocp->ioc_cmd);  				mutex_exit(&asy->asy_excl_hi);  				iocp->ioc_error = 0;  				mp->b_datap->db_type = M_IOCACK;  			} else {  				DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " -					"transparent\n", instance); +				    "transparent\n", instance);  				mcopyin(mp, NULL, sizeof (int), NULL);  			}  			break; @@ -3442,12 +3651,11 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  			if (iocp->ioc_count == TRANSPARENT) {  				DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " -					"transparent\n", instance); -				mcopyout(mp, NULL, sizeof (int), NULL, -					datamp); +				    "transparent\n", instance); +				mcopyout(mp, NULL, sizeof (int), NULL, datamp);  			} else {  				DEBUGCONT1(ASY_DEBUG_IOCTL, "async%d_ioctl: " -					"non-transparent\n", instance); +				    "non-transparent\n", instance);  				mioc2ack(mp, datamp, sizeof (int), 0);  			}  			break; @@ -3458,7 +3666,7 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  				break;  			*(struct cons_polledio **)mp->b_cont->b_rptr = -				&asy->polledio; +			    &asy->polledio;  			mp->b_datap->db_type = M_IOCACK;  			break; @@ -3498,7 +3706,7 @@ async_ioctl(struct asyncline *async, queue_t *wq, mblk_t *mp)  			 */  			mcopyout(mp, NULL, sizeof (boolean_t), NULL, NULL);  			*(boolean_t *)mp->b_cont->b_rptr = -				(asy->asy_flags & ASY_CONSOLE) != 0; +			    (asy->asy_flags & ASY_CONSOLE) != 0;  			break;  		default: @@ -3534,7 +3742,16 @@ asyrsrv(queue_t *q)  }  /* - * Put procedure for write queue. + * The ASYWPUTDO_NOT_SUSP macro indicates to asywputdo() whether it should + * handle messages as though the driver is operating normally or is + * suspended.  In the suspended case, some or all of the processing may have + * to be delayed until the driver is resumed. + */ +#define	ASYWPUTDO_NOT_SUSP(async, wput) \ +	!((wput) && ((async)->async_flags & ASYNC_DDI_SUSPENDED)) + +/* + * Processing for write queue put procedure.   * Respond to M_STOP, M_START, M_IOCTL, and M_FLUSH messages here;   * set the flow control character for M_STOPI and M_STARTI messages;   * queue up M_BREAK, M_DELAY, and M_DATA messages for processing @@ -3545,7 +3762,7 @@ asyrsrv(queue_t *q)   * as we do in ldterm.   */  static int -asywput(queue_t *q, mblk_t *mp) +asywputdo(queue_t *q, mblk_t *mp, boolean_t wput)  {  	struct asyncline *async;  	struct asycom *asy; @@ -3555,6 +3772,7 @@ asywput(queue_t *q, mblk_t *mp)  	int error;  	async = (struct asyncline *)q->q_ptr; +  #ifdef DEBUG  	instance = UNIT(async->async_dev);  #endif @@ -3577,17 +3795,19 @@ asywput(queue_t *q, mblk_t *mp)  		mutex_enter(&asy->asy_excl);  		if (async->async_flags & ASYNC_STOPPED) {  			async->async_flags &= ~ASYNC_STOPPED; -			/* -			 * If an output operation is in progress, -			 * resume it.  Otherwise, prod the start -			 * routine. -			 */ -			if (async->async_ocnt > 0) { -				mutex_enter(&asy->asy_excl_hi); -				async_resume(async); -				mutex_exit(&asy->asy_excl_hi); -			} else { -				async_start(async); +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				/* +				 * If an output operation is in progress, +				 * resume it.  Otherwise, prod the start +				 * routine. +				 */ +				if (async->async_ocnt > 0) { +					mutex_enter(&asy->asy_excl_hi); +					async_resume(async); +					mutex_exit(&asy->asy_excl_hi); +				} else { +					async_start(async); +				}  			}  		}  		mutex_exit(&asy->asy_excl); @@ -3606,19 +3826,21 @@ asywput(queue_t *q, mblk_t *mp)  			if (*(int *)mp->b_cont->b_rptr != 0) {  				DEBUGCONT1(ASY_DEBUG_OUT, -					"async%d_ioctl: flush request.\n", -					instance); +				    "async%d_ioctl: flush request.\n", +				    instance);  				(void) putq(q, mp); -				mutex_enter(&asy->asy_excl); -				/* -				 * If an TIOCSBRK is in progress, -				 * clean it as TIOCCBRK does, -				 * then kick off output. -				 * If TIOCSBRK is not in progress, -				 * just kick off output. -				 */ -				async_resume_utbrk(async); +				mutex_enter(&asy->asy_excl); +				if (ASYWPUTDO_NOT_SUSP(async, wput)) { +					/* +					 * If an TIOCSBRK is in progress, +					 * clean it as TIOCCBRK does, +					 * then kick off output. +					 * If TIOCSBRK is not in progress, +					 * just kick off output. +					 */ +					async_resume_utbrk(async); +				}  				mutex_exit(&asy->asy_excl);  				break;  			} @@ -3636,16 +3858,18 @@ asywput(queue_t *q, mblk_t *mp)  			 * start routine, just in case.  			 */  			(void) putq(q, mp); -			mutex_enter(&asy->asy_excl); -			/* -			 * If an TIOCSBRK is in progress, -			 * clean it as TIOCCBRK does. -			 * then kick off output. -			 * If TIOCSBRK is not in progress, -			 * just kick off output. -			 */ -			async_resume_utbrk(async); +			mutex_enter(&asy->asy_excl); +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				/* +				 * If an TIOCSBRK is in progress, +				 * clean it as TIOCCBRK does. +				 * then kick off output. +				 * If TIOCSBRK is not in progress, +				 * just kick off output. +				 */ +				async_resume_utbrk(async); +			}  			mutex_exit(&asy->asy_excl);  			break; @@ -3653,7 +3877,14 @@ asywput(queue_t *q, mblk_t *mp)  			/*  			 * Do it now.  			 */ -			async_ioctl(async, q, mp); +			mutex_enter(&asy->asy_excl); +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				mutex_exit(&asy->asy_excl); +				async_ioctl(async, q, mp); +				break; +			} +			async_put_suspq(asy, mp); +			mutex_exit(&asy->asy_excl);  			break;  		}  		break; @@ -3667,13 +3898,20 @@ asywput(queue_t *q, mblk_t *mp)  			 */  			mutex_enter(&asy->asy_excl_hi);  			if (async->async_flags & ASYNC_BUSY) { -			    DEBUGCONT1(ASY_DEBUG_BUSY, "asy%dwput: " +				DEBUGCONT1(ASY_DEBUG_BUSY, "asy%dwput: "  				    "Clearing async_ocnt, "  				    "leaving ASYNC_BUSY set\n",  				    instance);  				async->async_ocnt = 0;  				async->async_flags &= ~ASYNC_BUSY;  			} /* if */ + +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				/* Flush FIFO buffers */ +				if (asy->asy_use_fifo == FIFO_ON) { +					asy_reset_fifo(asy, FIFOTXFLSH); +				} +			}  			mutex_exit(&asy->asy_excl_hi);  			/* Flush FIFO buffers */ @@ -3693,9 +3931,11 @@ asywput(queue_t *q, mblk_t *mp)  			*mp->b_rptr &= ~FLUSHW;	/* it has been flushed */  		}  		if (*mp->b_rptr & FLUSHR) { -			/* Flush FIFO buffers */ -			if (asy->asy_use_fifo == FIFO_ON) { -				asy_reset_fifo(asy, FIFORXFLSH); +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				/* Flush FIFO buffers */ +				if (asy->asy_use_fifo == FIFO_ON) { +					asy_reset_fifo(asy, FIFORXFLSH); +				}  			}  			flushq(RD(q), FLUSHDATA);  			qreply(q, mp);	/* give the read queues a crack at it */ @@ -3707,9 +3947,11 @@ asywput(queue_t *q, mblk_t *mp)  		 * We must make sure we process messages that survive the  		 * write-side flush.  		 */ -		mutex_enter(&asy->asy_excl); -		async_start(async); -		mutex_exit(&asy->asy_excl); +		if (ASYWPUTDO_NOT_SUSP(async, wput)) { +			mutex_enter(&asy->asy_excl); +			async_start(async); +			mutex_exit(&asy->asy_excl); +		}  		break;  	case M_BREAK: @@ -3720,44 +3962,64 @@ asywput(queue_t *q, mblk_t *mp)  		 * and poke the start routine.  		 */  		(void) putq(q, mp); -		mutex_enter(&asy->asy_excl); -		async_start(async); -		mutex_exit(&asy->asy_excl); +		if (ASYWPUTDO_NOT_SUSP(async, wput)) { +			mutex_enter(&asy->asy_excl); +			async_start(async); +			mutex_exit(&asy->asy_excl); +		}  		break;  	case M_STOPI:  		mutex_enter(&asy->asy_excl); -		mutex_enter(&asy->asy_excl_hi); -		if (!(async->async_inflow_source & IN_FLOW_USER)) { -			async_flowcontrol_hw_input(asy, FLOW_STOP, -			    IN_FLOW_USER); -			(void) async_flowcontrol_sw_input(asy, FLOW_STOP, -			    IN_FLOW_USER); +		if (ASYWPUTDO_NOT_SUSP(async, wput)) { +			mutex_enter(&asy->asy_excl_hi); +			if (!(async->async_inflow_source & IN_FLOW_USER)) { +				async_flowcontrol_hw_input(asy, FLOW_STOP, +				    IN_FLOW_USER); +				(void) async_flowcontrol_sw_input(asy, +				    FLOW_STOP, IN_FLOW_USER); +			} +			mutex_exit(&asy->asy_excl_hi); +			mutex_exit(&asy->asy_excl); +			freemsg(mp); +			break;  		} -		mutex_exit(&asy->asy_excl_hi); +		async_put_suspq(asy, mp);  		mutex_exit(&asy->asy_excl); -		freemsg(mp);  		break;  	case M_STARTI:  		mutex_enter(&asy->asy_excl); -		mutex_enter(&asy->asy_excl_hi); -		if (async->async_inflow_source & IN_FLOW_USER) { -			async_flowcontrol_hw_input(asy, FLOW_START, -			    IN_FLOW_USER); -			(void) async_flowcontrol_sw_input(asy, FLOW_START, -			    IN_FLOW_USER); +		if (ASYWPUTDO_NOT_SUSP(async, wput)) { +			mutex_enter(&asy->asy_excl_hi); +			if (async->async_inflow_source & IN_FLOW_USER) { +				async_flowcontrol_hw_input(asy, FLOW_START, +				    IN_FLOW_USER); +				(void) async_flowcontrol_sw_input(asy, +				    FLOW_START, IN_FLOW_USER); +			} +			mutex_exit(&asy->asy_excl_hi); +			mutex_exit(&asy->asy_excl); +			freemsg(mp); +			break;  		} -		mutex_exit(&asy->asy_excl_hi); +		async_put_suspq(asy, mp);  		mutex_exit(&asy->asy_excl); -		freemsg(mp);  		break;  	case M_CTL:  		if (MBLKL(mp) >= sizeof (struct iocblk) &&  		    ((struct iocblk *)mp->b_rptr)->ioc_cmd == MC_POSIXQUERY) { -			((struct iocblk *)mp->b_rptr)->ioc_cmd = MC_HAS_POSIX; -			qreply(q, mp); +			mutex_enter(&asy->asy_excl); +			if (ASYWPUTDO_NOT_SUSP(async, wput)) { +				((struct iocblk *)mp->b_rptr)->ioc_cmd = +				    MC_HAS_POSIX; +				mutex_exit(&asy->asy_excl); +				qreply(q, mp); +				break; +			} else { +				async_put_suspq(asy, mp); +			}  		} else {  			/*  			 * These MC_SERVICE type messages are used by upper @@ -3784,7 +4046,14 @@ asywput(queue_t *q, mblk_t *mp)  		break;  	case M_IOCDATA: -		async_iocdata(q, mp); +		mutex_enter(&asy->asy_excl); +		if (ASYWPUTDO_NOT_SUSP(async, wput)) { +			mutex_exit(&asy->asy_excl); +			async_iocdata(q, mp); +			break; +		} +		async_put_suspq(asy, mp); +		mutex_exit(&asy->asy_excl);  		break;  	default: @@ -3794,6 +4063,12 @@ asywput(queue_t *q, mblk_t *mp)  	return (0);  } +static int +asywput(queue_t *q, mblk_t *mp) +{ +	return (asywputdo(q, mp, B_TRUE)); +} +  /*   * Retry an "ioctl", now that "bufcall" claims we may be able to allocate   * the buffer we need. @@ -3853,11 +4128,11 @@ async_iocdata(queue_t *q, mblk_t *mp)  	mutex_enter(&asy->asy_excl);  	DEBUGCONT2(ASY_DEBUG_MODEM, "async%d_iocdata: case %s\n", -		instance, -		csp->cp_cmd == TIOCMGET ? "TIOCMGET" : -		csp->cp_cmd == TIOCMSET ? "TIOCMSET" : -		csp->cp_cmd == TIOCMBIS ? "TIOCMBIS" : -		    "TIOCMBIC"); +	    instance, +	    csp->cp_cmd == TIOCMGET ? "TIOCMGET" : +	    csp->cp_cmd == TIOCMSET ? "TIOCMSET" : +	    csp->cp_cmd == TIOCMBIS ? "TIOCMBIS" : +	    "TIOCMBIC");  	switch (csp->cp_cmd) {  	case TIOCMGET: @@ -3876,9 +4151,8 @@ async_iocdata(queue_t *q, mblk_t *mp)  	case TIOCMBIS:  	case TIOCMBIC:  		mutex_enter(&asy->asy_excl_hi); -		(void) asymctl(asy, -			dmtoasy(*(int *)mp->b_cont->b_rptr), -			csp->cp_cmd); +		(void) asymctl(asy, dmtoasy(*(int *)mp->b_cont->b_rptr), +		    csp->cp_cmd);  		mutex_exit(&asy->asy_excl_hi);  		mioc2ack(mp, NULL, 0, 0);  		break; @@ -3927,8 +4201,8 @@ asyischar(cons_polledio_arg_t arg)  {  	struct asycom *asy = (struct asycom *)arg; -	return ((ddi_get8(asy->asy_iohandle, -		asy->asy_ioaddr + LSR) & RCA) != 0); +	return ((ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + LSR) & RCA) +	    != 0);  }  /* @@ -3941,8 +4215,7 @@ asygetchar(cons_polledio_arg_t arg)  	while (!asyischar(arg))  		drv_usecwait(10); -	return (ddi_get8(asy->asy_iohandle, -		asy->asy_ioaddr + DAT)); +	return (ddi_get8(asy->asy_iohandle, asy->asy_ioaddr + DAT));  }  /* @@ -3964,19 +4237,19 @@ asymctl(struct asycom *asy, int bits, int how)  	case TIOCMSET:  		DEBUGCONT2(ASY_DEBUG_MODEM, -			"asy%dmctl: TIOCMSET, bits = %x\n", instance, bits); +		    "asy%dmctl: TIOCMSET, bits = %x\n", instance, bits);  		mcr_r = bits;		/* Set bits	*/  		break;  	case TIOCMBIS:  		DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dmctl: TIOCMBIS, bits = %x\n", -			instance, bits); +		    instance, bits);  		mcr_r |= bits;		/* Mask in bits	*/  		break;  	case TIOCMBIC:  		DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dmctl: TIOCMBIC, bits = %x\n", -			instance, bits); +		    instance, bits);  		mcr_r &= ~bits;		/* Mask out bits */  		break; @@ -3990,17 +4263,17 @@ asymctl(struct asycom *asy, int bits, int how)  		    asy->asy_ioaddr + ICR) & MIEN) {  			msr_r = asy->asy_msr;  			DEBUGCONT2(ASY_DEBUG_MODEM, -				"asy%dmctl: TIOCMGET, read msr_r = %x\n", -				instance, msr_r); +			    "asy%dmctl: TIOCMGET, read msr_r = %x\n", +			    instance, msr_r);  		} else {  			msr_r = ddi_get8(asy->asy_iohandle, -					asy->asy_ioaddr + MSR); +			    asy->asy_ioaddr + MSR);  			DEBUGCONT2(ASY_DEBUG_MODEM, -				"asy%dmctl: TIOCMGET, read MSR = %x\n", -				instance, msr_r); +			    "asy%dmctl: TIOCMGET, read MSR = %x\n", +			    instance, msr_r);  		}  		DEBUGCONT2(ASY_DEBUG_MODEM, "asy%dtodm: modem_lines = %x\n", -			instance, asytodm(mcr_r, msr_r)); +		    instance, asytodm(mcr_r, msr_r));  		return (asytodm(mcr_r, msr_r));  	} diff --git a/usr/src/uts/common/io/audio/sada/drv/audio810/audio810.c b/usr/src/uts/common/io/audio/sada/drv/audio810/audio810.c index 19cc147773..5001635a43 100644 --- a/usr/src/uts/common/io/audio/sada/drv/audio810/audio810.c +++ b/usr/src/uts/common/io/audio/sada/drv/audio810/audio810.c @@ -19,7 +19,7 @@   * CDDL HEADER END   */  /* - * Copyright 2006 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ @@ -160,6 +160,8 @@ static uint_t	audio810_intr(caddr_t);  /*   * Local Routine Prototypes   */ +static void audio810_set_busy(audio810_state_t *); +static void audio810_set_idle(audio810_state_t *);  static int audio810_codec_sync(audio810_state_t *);  static int audio810_write_ac97(audio810_state_t *, int, uint16_t);  static int audio810_read_ac97(audio810_state_t *, int, uint16_t *); @@ -569,17 +571,49 @@ audio810_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  	switch (cmd) {  	case DDI_ATTACH:  		break; - -	/* -	 * now, no suspend/resume supported. we'll do it in the future. -	 */  	case DDI_RESUME:  		ATRACE("I810_attach() DDI_RESUME", NULL); -		audio_sup_log(NULL, CE_WARN, -		    "%s%d: i810_attach() resume is not supported yet", -		    audio810_name, instance); -		return (DDI_FAILURE); +		if ((statep = ddi_get_soft_state(audio810_statep, instance)) == +		    NULL) { +			audio_sup_log(NULL, CE_WARN, +			    "!attach() DDI_RESUME get soft state failed"); +			return (DDI_FAILURE); +		} + +		ASSERT(dip == statep->dip); + +		mutex_enter(&statep->inst_lock); + +		ASSERT(statep->i810_suspended == I810_SUSPENDED); + +		statep->i810_suspended = I810_NOT_SUSPENDED; + +		/* Restore the audio810 chip's state */ +		if (audio810_chip_init(statep, I810_INIT_RESTORE) != +		    AUDIO_SUCCESS) { +			audio_sup_log(statep->audio_handle, CE_WARN, +			    "!attach() DDI_RESUME failed to init chip"); +			mutex_exit(&statep->inst_lock); +			return (DDI_FAILURE); +		} + +		mutex_exit(&statep->inst_lock); + +		/* Resume playing and recording, if required */ +		if (audio_sup_restore_state(statep->audio_handle, +		    AUDIO_ALL_DEVICES, AUDIO_BOTH) == AUDIO_FAILURE) { +			audio_sup_log(statep->audio_handle, CE_WARN, +			    "!attach() DDI_RESUME audio restart failed"); +		} + +		mutex_enter(&statep->inst_lock); +		cv_broadcast(&statep->i810_cv);	/* let entry points continue */ +		mutex_exit(&statep->inst_lock); + +		ATRACE("audio810_attach() DDI_RESUME done", NULL); + +		return (DDI_SUCCESS);  	default:  		audio_sup_log(NULL, CE_WARN,  		    "!%s%d: attach() unknown command: 0x%x", @@ -638,7 +672,7 @@ audio810_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  	/* set PCI command register */  	cmdreg = pci_config_get16(statep->pci_conf_handle, PCI_CONF_COMM);  	pci_config_put16(statep->pci_conf_handle, PCI_CONF_COMM, -		cmdreg | PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME); +	    cmdreg | PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME);  	if ((audio810_alloc_sample_buf(statep, I810_DMA_PCM_OUT,  	    statep->play_buf_size) == AUDIO_FAILURE) || @@ -700,6 +734,7 @@ error_unmap:  error_destroy:  	ATRACE("audio810_attach() error_destroy", statep);  	mutex_destroy(&statep->inst_lock); +	cv_destroy(&statep->i810_cv);  error_audiosup:  	ATRACE("audio810_attach() error_audiosup", statep); @@ -751,17 +786,33 @@ audio810_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  	switch (cmd) {  	case DDI_DETACH:  		break; - -	/* -	 * now, no suspend/resume supported. we'll do it in the future. -	 */  	case DDI_SUSPEND:  		ATRACE("i810_detach() SUSPEND", statep); -		audio_sup_log(NULL, CE_WARN, -		    "%s%d: i810_detach() suspend is not supported yet", -		    audio810_name, instance); -		return (DDI_FAILURE); +		mutex_enter(&statep->inst_lock); + +		ASSERT(statep->i810_suspended == I810_NOT_SUSPENDED); + +		statep->i810_suspended = I810_SUSPENDED; /* stop new ops */ + +		/* wait for current operations to complete */ +		while (statep->i810_busy_cnt != 0) +			cv_wait(&statep->i810_cv, &statep->inst_lock); + +		/* stop DMA engines */ +		audio810_stop_dma(statep); + +		if (audio_sup_save_state(statep->audio_handle, +		    AUDIO_ALL_DEVICES, AUDIO_BOTH) == AUDIO_FAILURE) { +			audio_sup_log(statep->audio_handle, CE_WARN, +			    "!detach() DDI_SUSPEND audio save failed"); +		} + +		mutex_exit(&statep->inst_lock); + +		ATRACE("audio810_detach() DDI_SUSPEND successful", statep); + +		return (DDI_SUCCESS);  	default:  		ATRACE("i810_detach() unknown command", cmd);  		audio_sup_log(statep->audio_handle, CE_WARN, @@ -796,6 +847,7 @@ audio810_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  	(void) audio_sup_unregister(statep->audio_handle);  	mutex_destroy(&statep->inst_lock); +	cv_destroy(&statep->i810_cv);  	audio810_unmap_regs(statep); @@ -835,6 +887,13 @@ audio810_intr(caddr_t arg)  	statep = (audio810_state_t *)arg;  	mutex_enter(&statep->inst_lock); + +	if (statep->i810_suspended == I810_SUSPENDED) { +		ATRACE("audio810_intr() device suspended", NULL); +		mutex_exit(&statep->inst_lock); +		return (DDI_INTR_UNCLAIMED); +	} +  	gsr = I810_BM_GET32(I810_REG_GSR);  	/* check if device is interrupting */ @@ -883,6 +942,97 @@ audio810_intr(caddr_t arg)  }	/* audio810_intr() */ +/* + * audio810_set_busy() + * + * Description: + *	This routine is called whenever a routine needs to guarantee + *	that it will not be suspended.  It will also block any routine + *	while a suspend is going on. + * + *	CAUTION: This routine cannot be called by routines that will + *		block. Otherwise DDI_SUSPEND will be blocked for a + *		long time. And that is the wrong thing to do. + * + * Arguments: + *	audio810_state_t	*statep		The device's state structure + * + * Returns: + *	void + */ +static void +audio810_set_busy(audio810_state_t *statep) +{ +	ATRACE("in audio810_set_busy()", statep); + +	ASSERT(!mutex_owned(&statep->inst_lock)); + +	/* get the lock so we are safe */ +	mutex_enter(&statep->inst_lock); + +	/* block if we are suspended */ +	while (statep->i810_suspended == I810_SUSPENDED) { +		cv_wait(&statep->i810_cv, &statep->inst_lock); +	} + +	/* +	 * Okay, we aren't suspended, so mark as busy. +	 * This will keep us from being suspended when we release the lock. +	 */ +	ASSERT(statep->i810_busy_cnt >= 0); +	statep->i810_busy_cnt++; + +	mutex_exit(&statep->inst_lock); + +	ATRACE("audio810_set_busy() done", statep); + +	ASSERT(!mutex_owned(&statep->inst_lock)); + +}	/* audio810_set_busy() */ + +/* + * audio810_set_idle() + * + * Description: + *	This routine reduces the busy count. It then does a cv_broadcast() + *	if the count is 0 so a waiting DDI_SUSPEND will continue forward. + * + * Arguments: + *	audio810_state_t	*state		The device's state structure + * + * Returns: + *	void + */ +static void +audio810_set_idle(audio810_state_t *statep) +{ +	ATRACE("in audio810_set_idle()", statep); + +	ASSERT(!mutex_owned(&statep->inst_lock)); + +	/* get the lock so we are safe */ +	mutex_enter(&statep->inst_lock); + +	ASSERT(statep->i810_suspended == I810_NOT_SUSPENDED); + +	/* decrement the busy count */ +	ASSERT(statep->i810_busy_cnt > 0); +	statep->i810_busy_cnt--; + +	/* if no longer busy, then we wake up a waiting SUSPEND */ +	if (statep->i810_busy_cnt == 0) { +		cv_broadcast(&statep->i810_cv); +	} + +	/* we're done, so unlock */ +	mutex_exit(&statep->inst_lock); + +	ATRACE("audio810_set_idle() done", statep); + +	ASSERT(!mutex_owned(&statep->inst_lock)); + +}	/* audio810_set_idle() */ +  /* *********************** Mixer Entry Point Routines ******************* */  /*   * audio810_ad_set_config() @@ -926,6 +1076,8 @@ audio810_ad_set_config(audiohdl_t ahandle, int stream, int command,  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock);  	switch (command) {  	case AM_SET_GAIN: @@ -1030,6 +1182,8 @@ audio810_ad_set_config(audiohdl_t ahandle, int stream, int command,  	}  	mutex_exit(&statep->inst_lock); +	audio810_set_idle(statep); +  	ATRACE_32("i810_ad_set_config() returning", rc);  	return (rc); @@ -1063,6 +1217,7 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  {  	audio810_state_t	*statep;  	uint16_t		val; +	int			rc = AUDIO_FAILURE;  	ASSERT(precision == AUDIO_PRECISION_16);  	ASSERT(channels == AUDIO_CHANNELS_STEREO); @@ -1083,6 +1238,8 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock);  	if (statep->var_sr == B_FALSE) { @@ -1092,8 +1249,7 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  			audio_sup_log(statep->audio_handle, CE_NOTE,  			    "!ad_set_format() bad sample rate %d\n",  			    sample_rate); -			mutex_exit(&statep->inst_lock); -			return (AUDIO_FAILURE); +			goto done;  		}  	} else {  		switch (sample_rate) { @@ -1111,8 +1267,7 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  		case I810_SAMPR48000:	break;  		default:  			ATRACE_32("i810_ad_set_format() bad SR", sample_rate); -			mutex_exit(&statep->inst_lock); -			return (AUDIO_FAILURE); +			goto done;  		}  	} @@ -1140,8 +1295,7 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  				audio_sup_log(statep->audio_handle, CE_NOTE,  				    "!set_format() bad output sample rate %d",  				    sample_rate); -				mutex_exit(&statep->inst_lock); -				return (AUDIO_FAILURE); +				goto done;  			}  		} @@ -1170,8 +1324,7 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  				audio_sup_log(statep->audio_handle, CE_NOTE,  				    "!set_format() bad input sample rate %d",  				    sample_rate); -				mutex_exit(&statep->inst_lock); -				return (AUDIO_FAILURE); +				goto done;  			}  		} @@ -1180,12 +1333,15 @@ audio810_ad_set_format(audiohdl_t ahandle, int stream, int dir,  		statep->i810_cprecision = precision;  	} +	rc = AUDIO_SUCCESS;  done:  	mutex_exit(&statep->inst_lock); -	ATRACE_32("i810_ad_set_format() returning success", 0); +	audio810_set_idle(statep); -	return (AUDIO_SUCCESS); +	ATRACE_32("i810_ad_set_format() returning", rc); + +	return (rc);  }	/* audio810_ad_set_format() */ @@ -1215,6 +1371,8 @@ audio810_ad_start_play(audiohdl_t ahandle, int stream)  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock);  	if (statep->flags & I810_DMA_PLAY_PAUSED) { @@ -1239,6 +1397,9 @@ audio810_ad_start_play(audiohdl_t ahandle, int stream)  done:  	mutex_exit(&statep->inst_lock); + +	audio810_set_idle(statep); +  	return (rc);  }	/* audio810_ad_start_play() */ @@ -1269,17 +1430,20 @@ audio810_ad_pause_play(audiohdl_t ahandle, int stream)  	ATRACE("audio810_ad_pause_play() ", ahandle);  	ATRACE_32("i810_ad_pause_play() stream", stream); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock); -	if ((statep->flags & I810_DMA_PLAY_STARTED) == 0) { -		mutex_exit(&statep->inst_lock); -		return; -	} +	if ((statep->flags & I810_DMA_PLAY_STARTED) == 0) +		goto done;  	cr = I810_BM_GET8(I810_PCM_OUT_CR);  	cr &= ~I810_BM_CR_RUN;  	I810_BM_PUT8(I810_PCM_OUT_CR, cr);  	statep->flags |= I810_DMA_PLAY_PAUSED; +done:  	mutex_exit(&statep->inst_lock); +	audio810_set_idle(statep); +  }	/* audio810_ad_pause_play() */  /* @@ -1308,6 +1472,8 @@ audio810_ad_stop_play(audiohdl_t ahandle, int stream)  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock);  	/* pause bus master */ @@ -1323,6 +1489,8 @@ audio810_ad_stop_play(audiohdl_t ahandle, int stream)  	mutex_exit(&statep->inst_lock); +	audio810_set_idle(statep); +  }	/* audio810_ad_stop_play() */  /* @@ -1344,25 +1512,28 @@ static int  audio810_ad_start_record(audiohdl_t ahandle, int stream)  {  	audio810_state_t	*statep; -	int			rc; +	int			rc = AUDIO_SUCCESS;  	ATRACE("audio810_ad_start_record() ", ahandle);  	ATRACE_32("i810_ad_start_record() stream", stream);  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock); -	if (statep->flags & I810_DMA_RECD_STARTED) { -		mutex_exit(&statep->inst_lock); -		return (AUDIO_SUCCESS); -	} +	if (statep->flags & I810_DMA_RECD_STARTED) +		goto done;  	rc = audio810_prepare_record_buf(statep);  	if (rc == AUDIO_SUCCESS) {  		statep->flags |= I810_DMA_RECD_STARTED;  	} +done:  	mutex_exit(&statep->inst_lock); +	audio810_set_idle(statep); +  	return (rc);  }	/* audio810_ad_start_record() */ @@ -1393,6 +1564,8 @@ audio810_ad_stop_record(audiohdl_t ahandle, int stream)  	statep = audio_sup_get_private(ahandle);  	ASSERT(statep); +	audio810_set_busy(statep); +  	mutex_enter(&statep->inst_lock);  	statep->flags &= ~I810_DMA_RECD_STARTED; @@ -1407,6 +1580,8 @@ audio810_ad_stop_record(audiohdl_t ahandle, int stream)  	mutex_exit(&statep->inst_lock); +	audio810_set_idle(statep); +  }	/* audio810_ad_stop_record() */  /* *********************** Local Routines *************************** */ @@ -1585,6 +1760,7 @@ audio810_init_state(audio810_state_t *statep, dev_info_t *dip)  		return (AUDIO_FAILURE);  	}  	mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, statep->intr_iblock); +	cv_init(&statep->i810_cv, NULL, CV_DRIVER, NULL);  	/* fill in device info strings */  	(void) strcpy(statep->i810_dev_info.name, I810_DEV_NAME); @@ -2419,6 +2595,14 @@ audio810_stop_dma(audio810_state_t *statep)  	statep->flags = 0; +/* + * XXXX Not sure what these declarations are for, but I brought them from + * the PM gate. + */ +	statep->play_buf.io_started = B_FALSE; + +	statep->record_buf.io_started = B_FALSE; +  }	/* audio810_stop_dma() */  /* diff --git a/usr/src/uts/common/io/fdc.c b/usr/src/uts/common/io/fdc.c index ab8d9b9c18..0e111658e0 100644 --- a/usr/src/uts/common/io/fdc.c +++ b/usr/src/uts/common/io/fdc.c @@ -2,9 +2,8 @@   * CDDL HEADER START   *   * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License").  You may not use this file except in compliance - * with the License. + * 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   * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@   * CDDL HEADER END   */  /* - * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ @@ -472,7 +471,7 @@ fdc_probe(dev_info_t *dip)  	}  	FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_probe: dip %p", -		(void*)dip)); +	    (void*)dip));  	if (get_ioaddr(dip, &ioaddr) != DDI_SUCCESS)  		return (DDI_PROBE_FAILURE); @@ -497,7 +496,7 @@ fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  	char name[MAXNAMELEN];  	FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_attach: dip %p", -		(void*)dip)); +	    (void*)dip));  	switch (cmd) {  	case DDI_ATTACH: @@ -600,6 +599,10 @@ fdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  		ddi_report_dev(dip);  		return (DDI_SUCCESS); +	case DDI_RESUME: +		return (DDI_SUCCESS); +		/* break; */ +  	default:  		return (DDI_FAILURE);  	} @@ -826,11 +829,12 @@ static int  fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  {  	struct fdcntlr *fcp; +	struct fcu_obj *fjp;  	int unit;  	int rval = 0;  	FCERRPRINT(FDEP_L3, FDEM_ATTA, (CE_WARN, "fdc_detach: dip %p", -		(void*)dip)); +	    (void*)dip));  	fcp = ddi_get_driver_private(dip); @@ -847,8 +851,8 @@ fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  		if (ddi_dmae_release(fcp->c_dip, fcp->c_dmachan) !=  		    DDI_SUCCESS)  			cmn_err(CE_WARN, "fdc_detach: dma release failed, " -				"dip %p, dmachan %x\n", -				(void*)fcp->c_dip, fcp->c_dmachan); +			    "dip %p, dmachan %x\n", +			    (void*)fcp->c_dip, fcp->c_dmachan);  		ddi_prop_remove_all(fcp->c_dip);  		ddi_set_driver_private(fcp->c_dip, NULL); @@ -858,6 +862,35 @@ fdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  		sema_destroy(&fcp->c_selsem);  		ddi_soft_state_free(fdc_state_head, ddi_get_instance(dip));  		break; + +	case DDI_SUSPEND: +		/* +		 * Following code causes the fdc (floppy controller) +		 * to suspend as long as there are no floppy drives +		 * attached to it. +		 * At present the floppy driver does not support +		 * SUSPEND/RESUME. +		 * +		 * Check if any FD units are attached +		 * +		 * For now, SUSPEND/RESUME is not supported +		 * if a floppy drive is present. +		 * So if any FD unit is attached return DDI_FAILURE +		 */ +		for (unit = 0; unit < NFDUN; unit++) { +			fjp = fcp->c_unit[unit]; +			if (fjp->fj_flags & FUNIT_DRVATCH) { +				cmn_err(CE_WARN, +				    "fdc_detach: fd attached, failing SUSPEND"); +				return (DDI_FAILURE); +			} +		} + +		cmn_err(CE_NOTE, "fdc_detach: SUSPEND fdc"); + +		rval = DDI_SUCCESS; +		break; +  	default:  		rval = EINVAL;  		break; @@ -892,9 +925,9 @@ fdc_abort(struct fcu_obj *fjp)  			if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) !=  			    DDI_SUCCESS)  				cmn_err(CE_WARN, -					"fdc_detach: dma release failed, " -					"dip %p, dmachan %x\n", -					(void*)fcp->c_dip, fcp->c_dmachan); +				    "fdc_detach: dma release failed, " +				    "dip %p, dmachan %x\n", +				    (void*)fcp->c_dip, fcp->c_dmachan);  		}  		mutex_exit(&fcp->c_lock);  		drv_usecwait(500); @@ -923,7 +956,7 @@ fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp)  	struct fdcntlr *fcp = fjp->fj_fdc;  	(void) strncpy((char *)&dcp->dki_cname, ddi_get_name(fcp->c_dip), -		DK_DEVLEN); +	    DK_DEVLEN);  	dcp->dki_ctype = DKC_UNKNOWN; /* no code for generic PC/AT fdc */  	dcp->dki_flags = DKI_FMTTRK;  	dcp->dki_addr = fcp->c_regbase; @@ -931,7 +964,7 @@ fdc_dkinfo(struct fcu_obj *fjp, struct dk_cinfo *dcp)  	dcp->dki_prio = fcp->c_intprio;  	dcp->dki_vec = fcp->c_intvec;  	(void) strncpy((char *)&dcp->dki_dname, ddi_driver_name(fjp->fj_dip), -		DK_DEVLEN); +	    DK_DEVLEN);  	dcp->dki_slave = fjp->fj_unit & 3;  	dcp->dki_maxtransfer = maxphys / DEV_BSIZE;  	return (DDI_SUCCESS); @@ -1149,7 +1182,7 @@ fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head,  	dmar_flags |= (DDI_DMA_STREAMING | DDI_DMA_PARTIAL);  	if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, -			0, &csb->csb_dmahandle) != DDI_SUCCESS) { +	    0, &csb->csb_dmahandle) != DDI_SUCCESS) {  		rval = EINVAL;  		goto out;  	} @@ -1181,15 +1214,14 @@ fdrw(struct fcu_obj *fjp, int funit, int rw, int cyl, int head,  	} else if (rval == DDI_DMA_PARTIAL_MAP) {  		csb->csb_handle_bound = 1;  		if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != -					DDI_SUCCESS) { +		    DDI_SUCCESS) {  			cmn_err(CE_WARN, "fdrw: dma numwin failed\n");  			rval = EINVAL;  			goto out;  		}  	} else {  		cmn_err(CE_WARN, -			"fdrw: dma addr bind handle failed, rval = %d\n", -			rval); +		    "fdrw: dma addr bind handle failed, rval = %d\n", rval);  		rval = EINVAL;  		goto out;  	} @@ -1269,7 +1301,7 @@ fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata)  	fmdatlen = 4 * numsctr;  	if (ddi_dma_alloc_handle(fcp->c_dip, &fdc_dma_attr, DDI_DMA_SLEEP, -			0, &csb->csb_dmahandle) != DDI_SUCCESS) { +	    0, &csb->csb_dmahandle) != DDI_SUCCESS) {  		rval = EINVAL;  		goto out;  	} @@ -1310,15 +1342,15 @@ fdtrkformat(struct fcu_obj *fjp, int funit, int cyl, int head, int filldata)  	} else if (rval == DDI_DMA_PARTIAL_MAP) {  		csb->csb_handle_bound = 1;  		if (ddi_dma_numwin(csb->csb_dmahandle, &csb->csb_dmawincnt) != -					DDI_SUCCESS) { +		    DDI_SUCCESS) {  			cmn_err(CE_WARN, "fdtrkformat: dma numwin failed\n");  			rval = EINVAL;  			goto out;  		}  	} else {  		cmn_err(CE_WARN, -			"fdtrkformat: dma buf bind handle failed, rval = %d\n", -			rval); +		    "fdtrkformat: dma buf bind handle failed, rval = %d\n", +		    rval);  		rval = EINVAL;  		goto out;  	} @@ -1579,15 +1611,15 @@ fdcquiesce(struct fdcntlr *fcp)  	int unit;  	FCERRPRINT(FDEP_L2, FDEM_RESE, (CE_NOTE, "fdcquiesce fcp %p", -		(void*)fcp)); +	    (void*)fcp));  	ASSERT(MUTEX_HELD(&fcp->c_lock));  	mutex_enter(&fcp->c_dorlock);  	if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS)  		cmn_err(CE_WARN, "fdcquiesce: dmae stop failed, " -			"dip %p, dmachan %x\n", -			(void*)fcp->c_dip, fcp->c_dmachan); +		    "dip %p, dmachan %x\n", +		    (void*)fcp->c_dip, fcp->c_dmachan);  	fcp->c_digout = (fcp->c_digout & (FD_DMTREN | FD_DRSEL)) | FD_ENABLE;  	outb(fcp->c_regbase + FCR_DOR, fcp->c_digout); @@ -2158,7 +2190,7 @@ retry:  		 */  		mutex_enter(&fcp->c_dorlock);  		(void) fdc_motorsm(fjp, FMI_RSTARTCMD, -			fjp->fj_drive->fdd_motoron); +		    fjp->fj_drive->fdd_motoron);  		/*  		 * Return value ignored - fdcmotort deals with failure.  		 */ @@ -2202,8 +2234,8 @@ retry:  		if (ddi_dmae_prog(fcp->c_dip, &dmaereq, &csb->csb_dmacookie,  		    fcp->c_dmachan) != DDI_SUCCESS)  			cmn_err(CE_WARN, "fdc_exec: dmae prog failed, " -				"dip %p, dmachan %x\n", -				(void*)fcp->c_dip, fcp->c_dmachan); +			    "dip %p, dmachan %x\n", +			    (void*)fcp->c_dip, fcp->c_dmachan);  	}  	if ((fdc_statemach(fcp) == FXS_DOWT) && !sleep) { @@ -2400,7 +2432,9 @@ fdrecover(struct fdcntlr *fcp)  				    (void*)fcp->c_dip, fcp->c_dmachan,  				    residual);  			FCERRPRINT(FDEP_L2, FDEM_RECO, -	(CE_NOTE, "fd unit %d: %s error: dma count=0x%lx residual=0x%x", +			    (CE_NOTE, +			    "fd unit %d: %s error: " +			    "dma count=0x%lx residual=0x%x",  			    csb->csb_drive,  			    fdcmds[*csb->csb_cmd & 0x1f].cmdname,  			    csb->csb_dmacookie.dmac_size, residual)); @@ -2412,8 +2446,10 @@ fdrecover(struct fdcntlr *fcp)  			 */  			if (++csb->csb_ourtrys <= OURUN_TRIES) {  				FCERRPRINT(FDEP_L2, FDEM_RECO, -(CE_NOTE, "fd unit %d: %s error: over/under-run", -csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname)); +				    (CE_NOTE, +				    "fd unit %d: %s error: over/under-run", +				    csb->csb_drive, +				    fdcmds[*csb->csb_cmd & 0x1f].cmdname));  				return (0);  			} else  				/* @@ -2445,9 +2481,12 @@ csb->csb_drive, fdcmds[*csb->csb_cmd & 0x1f].cmdname));  				if (csb->csb_opflags &  				    (CSB_OFDMARD | CSB_OFDMAWT)) {  					FCERRPRINT(FDEP_L4, FDEM_RECO, -(CE_WARN, "fd unit %d: %s error: st0=0x%x st1=0x%x st2=0x%x", +					    (CE_WARN, +					    "fd unit %d: %s error: " +					    "st0=0x%x st1=0x%x st2=0x%x",  					    csb->csb_drive, -fdcmds[*csb->csb_cmd & 0x1f].cmdname, +					    fdcmds[*csb->csb_cmd & +					    0x1f].cmdname,  					    *csb->csb_rslt, csb->csb_rslt[1],  					    csb->csb_rslt[2]));  				} @@ -2681,8 +2720,8 @@ fdwatch(void *arg)  	if (fcp->c_flags & FCFLG_WAITING) {  		if (ddi_dmae_stop(fcp->c_dip, fcp->c_dmachan) != DDI_SUCCESS)  			cmn_err(CE_WARN, "fdwatch: dmae stop failed, " -				"dip %p, dmachan %x\n", -				(void*)fcp->c_dip, fcp->c_dmachan); +			    "dip %p, dmachan %x\n", +			    (void*)fcp->c_dip, fcp->c_dmachan);  		csb = &fcp->c_csb;  		FCERRPRINT(FDEP_L3, FDEM_WATC,  		    (CE_WARN, "fdcwatch unit %d: xstate = %d", @@ -3168,7 +3207,7 @@ get_ioaddr(dev_info_t *dip, int *ioaddr)  	} *reglist;  	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, -		"reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) { +	    "reg", (caddr_t)®list, ®len) != DDI_PROP_SUCCESS) {  		cmn_err(CE_WARN, "fdc: reg property not found");  		return (DDI_FAILURE);  	} diff --git a/usr/src/uts/common/io/i8042.c b/usr/src/uts/common/io/i8042.c index 42bcbb8d2a..9c9e568abc 100644 --- a/usr/src/uts/common/io/i8042.c +++ b/usr/src/uts/common/io/i8042.c @@ -382,6 +382,23 @@ static void i8042_send(struct i8042 *global, int reg, unsigned char cmd);  unsigned int i8042_unclaimed_interrupts = 0; +static void +i8042_discard_junk_data(struct i8042 *global) +{ +	/* Discard any junk data that may have been left around */ +	for (;;) { +		unsigned char		stat; + +		stat = ddi_get8(global->io_handle, +		    global->io_addr + I8042_STAT); +		if (! (stat & I8042_STAT_OUTBF)) +			break; +		(void) ddi_get8(global->io_handle, +		    global->io_addr + I8042_DATA); + +	} +} +  static int  i8042_cleanup(struct i8042 *global)  { @@ -508,7 +525,7 @@ i8042_purge_outbuf(struct i8042 *global)  		if (i8042_wait_obf(global))  			break;  		(void) ddi_get8(global->io_handle, -			global->io_addr + I8042_DATA); +		    global->io_addr + I8042_DATA);  	}  	/* @@ -537,10 +554,9 @@ i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  	switch (cmd) {  	case DDI_RESUME: -#ifdef __sparc  		global = (struct i8042 *)ddi_get_driver_private(dip); +		i8042_discard_junk_data(global);  		i8042_write_command_byte(global, I8042_CMD_ENABLE_ALL); -#endif  		return (DDI_SUCCESS);  	case DDI_ATTACH: @@ -628,7 +644,7 @@ i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  		global->iblock_cookies = NULL;  	mutex_init(&global->i8042_mutex, NULL, MUTEX_DRIVER, -		(global->nintrs > 0) ? global->iblock_cookies[0] : NULL); +	    (global->nintrs > 0) ? global->iblock_cookies[0] : NULL);  	mutex_init(&global->i8042_out_mutex, NULL, MUTEX_DRIVER, NULL); @@ -816,8 +832,8 @@ i8042_map(  		}  		if (rnumber < 0 || rnumber >= iprop_len) {  			cmn_err(CE_WARN, "%s #%d:  bad map request for %s@%s", -				DRIVER_NAME(dip), ddi_get_instance(dip), -				ddi_node_name(rdip), ddi_get_name_addr(rdip)); +			    DRIVER_NAME(dip), ddi_get_instance(dip), +			    ddi_node_name(rdip), ddi_get_name_addr(rdip));  			return (DDI_FAILURE);  		}  #endif @@ -838,9 +854,9 @@ i8042_map(  	default:  #if defined(DEBUG)  		cmn_err(CE_WARN, "%s #%d:  unknown map type %d for %s@%s", -			DRIVER_NAME(dip), ddi_get_instance(dip), -			mp->map_type, -			ddi_node_name(rdip), ddi_get_name_addr(rdip)); +		    DRIVER_NAME(dip), ddi_get_instance(dip), +		    mp->map_type, +		    ddi_node_name(rdip), ddi_get_name_addr(rdip));  #endif  		return (DDI_FAILURE);  	} @@ -848,9 +864,9 @@ i8042_map(  #if defined(DEBUG)  	if (offset != 0 || len != 0) {  		cmn_err(CE_WARN, -			"%s #%d:  partial mapping attempt for %s@%s ignored", -				DRIVER_NAME(dip), ddi_get_instance(dip), -				ddi_node_name(rdip), ddi_get_name_addr(rdip)); +		    "%s #%d:  partial mapping attempt for %s@%s ignored", +		    DRIVER_NAME(dip), ddi_get_instance(dip), +		    ddi_node_name(rdip), ddi_get_name_addr(rdip));  	}  #endif @@ -901,7 +917,7 @@ i8042_map(  	default:  		cmn_err(CE_WARN, "%s:  map operation %d not supported", -			DRIVER_NAME(dip), mp->map_op); +		    DRIVER_NAME(dip), mp->map_op);  		return (DDI_FAILURE);  	}  } @@ -986,7 +1002,7 @@ i8042_intr(caddr_t arg)  #if defined(DEBUG)  		if (port->overruns % 50 == 1) {  			cmn_err(CE_WARN, "i8042/%d: %d overruns\n", -				which_port, port->overruns); +			    which_port, port->overruns);  		}  #endif  		mutex_exit(&global->i8042_mutex); @@ -1039,7 +1055,7 @@ i8042_send(struct i8042 *global, int reg, unsigned char val)  	/*CONSTANTCONDITION*/  	while (1) {  		stat = ddi_get8(global->io_handle, -			global->io_addr + I8042_STAT); +		    global->io_addr + I8042_STAT);  		if ((stat & I8042_STAT_INBF) == 0) {  			ddi_put8(global->io_handle, global->io_addr+reg, val); @@ -1113,7 +1129,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  		} else {  #if defined(DEBUG)  			cmn_err(CE_WARN, -				"i8042:  Tried to read from empty buffer"); +			    "i8042:  Tried to read from empty buffer");  #endif  			ret = 0;  		} @@ -1127,7 +1143,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  	case I8042_INT_OUTPUT_DATA:  	case I8042_POLL_OUTPUT_DATA:  		cmn_err(CE_WARN, "i8042:  read of write-only register 0x%p", -			(void *)addr); +		    (void *)addr);  		ret = 0;  		break;  #endif @@ -1137,7 +1153,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  			return (B_TRUE);  		for (;;) {  			stat = ddi_get8(global->io_handle, -				global->io_addr + I8042_STAT); +			    global->io_addr + I8042_STAT);  			if ((stat & I8042_STAT_OUTBF) == 0)  				return (B_FALSE);  			switch (port->which) { @@ -1151,13 +1167,13 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  				break;  			default:  				cmn_err(CE_WARN, "data from unknown port: %d", -					port->which); +				    port->which);  			}  			/*  			 * Data for wrong port pending; discard it.  			 */  			(void) ddi_get8(global->io_handle, -					global->io_addr + I8042_DATA); +			    global->io_addr + I8042_DATA);  		}  		/* NOTREACHED */ @@ -1170,7 +1186,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  		}  		stat = ddi_get8(global->io_handle, -			    global->io_addr + I8042_STAT); +		    global->io_addr + I8042_STAT);  		if ((stat & I8042_STAT_OUTBF) == 0) {  #if defined(DEBUG)  			prom_printf("I8042_POLL_INPUT_DATA:  no data!\n"); @@ -1178,7 +1194,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  			return (0);  		}  		ret = ddi_get8(global->io_handle, -			    global->io_addr + I8042_DATA); +		    global->io_addr + I8042_DATA);  		switch (port->which) {  		case MAIN_PORT:  			if ((stat & I8042_STAT_AUXBF) == 0) @@ -1197,7 +1213,7 @@ i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr)  	default:  #if defined(DEBUG)  		cmn_err(CE_WARN, "i8042:  read of undefined register 0x%p", -			(void *)addr); +		    (void *)addr);  #endif  		ret = 0;  		break; @@ -1240,12 +1256,12 @@ i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value)  	case I8042_POLL_INPUT_AVAIL:  	case I8042_POLL_INPUT_DATA:  		cmn_err(CE_WARN, "i8042:  write of read-only register 0x%p", -			(void *)addr); +		    (void *)addr);  		break;  	default:  		cmn_err(CE_WARN, "i8042:  read of undefined register 0x%p", -			(void *)addr); +		    (void *)addr);  		break;  #endif  	} @@ -1391,7 +1407,7 @@ i8042_ctlops(dev_info_t *dip, dev_info_t *rdip,  		(void) sprintf(name, "%d", which_port);  		ddi_set_name_addr(child, name);  		ddi_set_parent_data(child, -			(caddr_t)&global->i8042_ports[which_port]); +		    (caddr_t)&global->i8042_ports[which_port]);  		return (DDI_SUCCESS);  	case DDI_CTLOPS_UNINITCHILD: @@ -1402,8 +1418,8 @@ i8042_ctlops(dev_info_t *dip, dev_info_t *rdip,  	case DDI_CTLOPS_REPORTDEV:  		cmn_err(CE_CONT, "?8042 device:  %s@%s, %s # %d\n", -			ddi_node_name(rdip), ddi_get_name_addr(rdip), -			DRIVER_NAME(rdip), ddi_get_instance(rdip)); +		    ddi_node_name(rdip), ddi_get_name_addr(rdip), +		    DRIVER_NAME(rdip), ddi_get_instance(rdip));  		return (DDI_SUCCESS);  	default: diff --git a/usr/src/uts/common/io/kb8042/kb8042.c b/usr/src/uts/common/io/kb8042/kb8042.c index 6799e6d75a..0e8369b076 100644 --- a/usr/src/uts/common/io/kb8042/kb8042.c +++ b/usr/src/uts/common/io/kb8042/kb8042.c @@ -431,6 +431,14 @@ kb8042_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)  		kb8042->w_init = 0;  		kb8042_init(kb8042, B_TRUE);  		kb8042_setled(kb8042, leds, B_FALSE); +		mutex_enter(&kb8042->w_hw_mutex); +		kb8042->suspended = B_FALSE; +		if (kb8042->w_qp != NULL) { +			enableok(WR(kb8042->w_qp)); +			qenable(WR(kb8042->w_qp)); +		} +		cv_broadcast(&kb8042->suspend_cv); +		mutex_exit(&kb8042->w_hw_mutex);  		return (DDI_SUCCESS);  	case DDI_ATTACH: @@ -480,7 +488,8 @@ kb8042_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)  	}  	mutex_init(&kb8042->w_hw_mutex, NULL, MUTEX_DRIVER, kb8042->w_iblock); - +	cv_init(&kb8042->ops_cv, NULL, CV_DRIVER, NULL); +	cv_init(&kb8042->suspend_cv, NULL, CV_DRIVER, NULL);  	kb8042->init_state |= KB8042_HW_MUTEX_INITTED;  	kb8042_init(kb8042, B_FALSE); @@ -552,6 +561,12 @@ kb8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  	switch (cmd) {  	case DDI_SUSPEND: +		mutex_enter(&kb8042->w_hw_mutex); +		ASSERT(kb8042->ops >= 0); +		while (kb8042->ops > 0) +			cv_wait(&kb8042->ops_cv, &kb8042->w_hw_mutex); +		kb8042->suspended = B_TRUE; +		mutex_exit(&kb8042->w_hw_mutex);  		return (DDI_SUCCESS);  	case DDI_DETACH: @@ -606,8 +621,11 @@ kb8042_cleanup(struct kb8042 *kb8042)  {  	ASSERT(kb8042_dip != NULL); -	if (kb8042->init_state & KB8042_HW_MUTEX_INITTED) +	if (kb8042->init_state & KB8042_HW_MUTEX_INITTED) { +		cv_destroy(&kb8042->suspend_cv); +		cv_destroy(&kb8042->ops_cv);  		mutex_destroy(&kb8042->w_hw_mutex); +	}  	if (kb8042->init_state & KB8042_INTR_ADDED)  		ddi_remove_intr(kb8042_dip, 0, kb8042->w_iblock); @@ -660,9 +678,19 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)  	kb8042 = &Kdws; +	mutex_enter(&kb8042->w_hw_mutex); +	while (kb8042->suspended) { +		if (cv_wait_sig(&kb8042->suspend_cv, &kb8042->w_hw_mutex) == +		    0) { +			mutex_exit(&kb8042->w_hw_mutex); +			return (EINTR); +		} +	} +  	kb8042->w_dev = *devp;  	if (qp->q_ptr) { +		mutex_exit(&kb8042->w_hw_mutex);  		return (0);  	}  	qp->q_ptr = (caddr_t)kb8042; @@ -670,6 +698,10 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)  	if (!kb8042->w_qp)  		kb8042->w_qp = qp; +	ASSERT(kb8042->ops >= 0); +	kb8042->ops++; +	mutex_exit(&kb8042->w_hw_mutex); +  	kb8042_get_initial_leds(kb8042, &initial_leds, &initial_led_mask);  	err = kbtrans_streams_init(qp, sflag, credp,  	    (struct kbtrans_hardware *)kb8042, &kb8042_callbacks, @@ -700,6 +732,13 @@ kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)  	kbtrans_streams_enable(kb8042->hw_kbtrans); +	mutex_enter(&kb8042->w_hw_mutex); +	ASSERT(kb8042->ops > 0); +	kb8042->ops--; +	if (kb8042->ops == 0) +		cv_broadcast(&kb8042->ops_cv); +	mutex_exit(&kb8042->w_hw_mutex); +  	return (0);  } @@ -714,11 +753,31 @@ kb8042_close(queue_t *qp, int flag, cred_t *credp)  	kb8042 = (struct kb8042 *)qp->q_ptr; +	mutex_enter(&kb8042->w_hw_mutex); +	while (kb8042->suspended) { +		if (cv_wait_sig(&kb8042->suspend_cv, &kb8042->w_hw_mutex) == +		    0) { +			mutex_exit(&kb8042->w_hw_mutex); +			return (EINTR); +		} +	} + +	ASSERT(kb8042->ops >= 0); +	kb8042->ops++; +	mutex_exit(&kb8042->w_hw_mutex); +  	(void) kbtrans_streams_fini(kb8042->hw_kbtrans);  	kb8042->w_qp = (queue_t *)NULL;  	qprocsoff(qp); +	mutex_enter(&kb8042->w_hw_mutex); +	ASSERT(kb8042->ops > 0); +	kb8042->ops--; +	if (kb8042->ops == 0) +		cv_broadcast(&kb8042->ops_cv); +	mutex_exit(&kb8042->w_hw_mutex); +  	return (0);  } @@ -728,10 +787,27 @@ kb8042_wsrv(queue_t *qp)  	struct kb8042 *kb8042;  	mblk_t	*mp; +	boolean_t suspended;  	kb8042 = (struct kb8042 *)qp->q_ptr; +	mutex_enter(&kb8042->w_hw_mutex); +	suspended = kb8042->suspended; +	ASSERT(kb8042->ops >= 0); +	if (!suspended) +		kb8042->ops++; +	mutex_exit(&kb8042->w_hw_mutex); + +#ifdef NO_KB_DEBUG +	while (!suspended && (mp = getq(qp)) != NULL) { +#else +	/* +	 * Not taking keyboard input while suspending can make debugging +	 * difficult.  However, we still do the ops counting so that we +	 * don't suspend at a bad time. +	 */  	while ((mp = getq(qp))) { +#endif  		switch (kbtrans_streams_message(kb8042->hw_kbtrans, mp)) {  		case KBTRANS_MESSAGE_HANDLED:  			continue; @@ -765,6 +841,16 @@ kb8042_wsrv(queue_t *qp)  			continue;  		}  	} + +	mutex_enter(&kb8042->w_hw_mutex); +	if (!suspended) { +		ASSERT(kb8042->ops > 0); +		kb8042->ops--; +		if (kb8042->ops == 0) +			cv_broadcast(&kb8042->ops_cv); +	} +	mutex_exit(&kb8042->w_hw_mutex); +  	return (0);  } diff --git a/usr/src/uts/common/io/kb8042/kb8042.h b/usr/src/uts/common/io/kb8042/kb8042.h index 33d849669e..6232d38279 100644 --- a/usr/src/uts/common/io/kb8042/kb8042.h +++ b/usr/src/uts/common/io/kb8042/kb8042.h @@ -2,9 +2,8 @@   * CDDL HEADER START   *   * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License").  You may not use this file except in compliance - * with the License. + * 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   * or http://www.opensolaris.org/os/licensing. @@ -19,12 +18,13 @@   *   * CDDL HEADER END   */ +  /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/  /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/  /*	  All Rights Reserved  	*/  /* - * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ @@ -111,6 +111,10 @@ struct kb8042 {  	int		simulated_kbd_type;  	uint32_t	init_state;  	int		break_received; +	boolean_t	suspended; +	int		ops; +	kcondvar_t	suspend_cv; +	kcondvar_t	ops_cv;  };  #define	KB_COMMAND_STATE_IDLE	0 diff --git a/usr/src/uts/common/io/pci-ide/pci-ide.c b/usr/src/uts/common/io/pci-ide/pci-ide.c index c47157dd31..924aec38d7 100644 --- a/usr/src/uts/common/io/pci-ide/pci-ide.c +++ b/usr/src/uts/common/io/pci-ide/pci-ide.c @@ -19,7 +19,7 @@   * CDDL HEADER END   */  /* - * Copyright 2006 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ @@ -47,6 +47,7 @@  #include <sys/pci_intr_lib.h>  int	pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +int	pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);  #define	PCIIDE_NATIVE_MODE(dip)						\  	(!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, 	\ @@ -154,7 +155,7 @@ struct dev_ops pciide_ops = {  	nulldev,		/* identify */  	nulldev,		/* probe */  	pciide_attach,		/* attach */ -	nodev,			/* detach */ +	pciide_detach,		/* detach */  	nodev,			/* reset */  	(struct cb_ops *)0,	/* driver operations */  	&pciide_bus_ops	/* bus operations */ @@ -203,9 +204,8 @@ pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  	ddi_acc_handle_t conf_hdl = NULL;  	int rc; - -	if (cmd == DDI_ATTACH) { - +	switch (cmd) { +	case DDI_ATTACH:  		/*  		 * Make sure bus-mastering is enabled, even if  		 * BIOS didn't. @@ -225,13 +225,55 @@ pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  			    cmdreg | PCI_COMM_ME);  		}  		pci_config_teardown(&conf_hdl); +		return (DDI_SUCCESS); +	case DDI_RESUME: +		/* Restore our PCI configuration header */ +		if (pci_restore_config_regs(dip) != DDI_SUCCESS) { +			/* +			 * XXXX +			 * This is a pretty bad thing.  However, for some +			 * reason it always happens.  To further complicate +			 * things, it appears if we just ignore this, we +			 * properly resume.  For now, all I want to do is +			 * to generate this message so that it doesn't get +			 * forgotten. +			 */ +			cmn_err(CE_WARN, +			    "Couldn't restore PCI config regs for %s(%p)", +			    ddi_node_name(dip), (void *) dip); +		} +#ifdef	DEBUG +		/* Bus mastering should still be enabled */ +		if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS) +			return (DDI_FAILURE); +		cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM); +		ASSERT((cmdreg & PCI_COMM_ME) != 0); +		pci_config_teardown(&conf_hdl); +#endif  		return (DDI_SUCCESS); -	} else { -		return (DDI_FAILURE);  	} + +	return (DDI_FAILURE);  } +/*ARGSUSED*/ +int +pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ +	switch (cmd) { +	case DDI_DETACH: +		return (DDI_SUCCESS); +	case DDI_SUSPEND: +		/* Save our PCI configuration header */ +		if (pci_save_config_regs(dip) != DDI_SUCCESS) { +			/* Don't suspend if we cannot save config regs */ +			return (DDI_FAILURE); +		} +		return (DDI_SUCCESS); +	} +	return (DDI_FAILURE); +}  /*ARGSUSED*/  static int @@ -295,9 +337,9 @@ pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,  			old_rnumber = rnumber;  			new_rnumber -				= pciide_pre26_rnumber_map(dip, old_rnumber); +			    = pciide_pre26_rnumber_map(dip, old_rnumber);  			PDBG(("pciide rnumber old %d new %d\n", -				old_rnumber, new_rnumber)); +			    old_rnumber, new_rnumber));  			rnumber = new_rnumber;  		} @@ -454,7 +496,7 @@ pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)  		 * property in the ata.conf file.  		 */  		vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, -				"interrupts", -1); +		    "interrupts", -1);  		if (vec == -1) {  			/* setup compatibility mode interrupts */  			if (dev == 0) { @@ -530,7 +572,7 @@ pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,  		old_rnumber = mp->map_obj.rnumber;  		new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);  		PDBG(("pciide rnumber old %d new %d\n", -			old_rnumber, new_rnumber)); +		    old_rnumber, new_rnumber));  		mp->map_obj.rnumber = new_rnumber;  	} @@ -545,7 +587,7 @@ pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,  	 */  	pdip = ddi_get_parent(dip);  	rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)) -			(pdip, dip, mp, offset, len, vaddrp)); +	    (pdip, dip, mp, offset, len, vaddrp));  	PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok")); @@ -751,7 +793,7 @@ pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)  		if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||  		    (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {  			rc = ddi_prop_update_int(DDI_DEV_T_NONE, cdip, -					"compatibility-mode", 1); +			    "compatibility-mode", 1);  			if (rc != DDI_PROP_SUCCESS)  				cmn_err(CE_WARN,  				    "pciide prop error %d compat-mode", rc); @@ -765,9 +807,9 @@ pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)  		 */  		class_code &= 0x00ffff00;  		class_code |= PCI_IDE_IF_BM_CAP_MASK | -			PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC; +		    PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;  		rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip, -			"class-code", class_code); +		    "class-code", class_code);  		if (rc != DDI_PROP_SUCCESS)  			cmn_err(CE_WARN,  			    "pciide prop error %d class-code", rc); @@ -783,7 +825,7 @@ pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)  	int	class_code;  	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS, -				"class-code", 0); +	    "class-code", 0);  	pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;  	sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE; diff --git a/usr/src/uts/common/io/pm.c b/usr/src/uts/common/io/pm.c index d4cb7f0da0..42847eecf7 100644 --- a/usr/src/uts/common/io/pm.c +++ b/usr/src/uts/common/io/pm.c @@ -56,10 +56,10 @@  #include <sys/policy.h>  /* - * Minor number is instance<<8 + clone minor from range 1-255; (0 reserved - * for "original" + * Minor number is instance<<8 + clone minor from range 1-254; (0 reserved + * for "original")   */ -#define	PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE - 1)) +#define	PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE -1))  #define	PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components)  #define	PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB) @@ -67,6 +67,8 @@  #define	PM_RELE(dip) ddi_release_devi(dip)  #define	PM_IDLEDOWN_TIME	10 +#define	MAXSMBIOSSTRLEN 64	/* from SMBIOS spec */ +#define	MAXCOPYBUF 	(MAXSMBIOSSTRLEN + 1)  extern kmutex_t	pm_scan_lock;	/* protects autopm_enable, pm_scans_disabled */  extern kmutex_t	pm_clone_lock;	/* protects pm_clones array */ @@ -77,6 +79,19 @@ extern int	pm_system_idle_threshold;  extern int	pm_cpu_idle_threshold;  extern kcondvar_t pm_clones_cv[PM_MAX_CLONE];  extern uint_t	pm_poll_cnt[PM_MAX_CLONE]; +extern int	autoS3_enabled; +extern void	pm_record_thresh(pm_thresh_rec_t *); +extern void	pm_register_watcher(int, dev_info_t *); +extern int	pm_get_current_power(dev_info_t *, int, int *); +extern int	pm_interest_registered(int); +extern void	pm_all_to_default_thresholds(void); +extern int	pm_current_threshold(dev_info_t *, int, int *); +extern void	pm_deregister_watcher(int, dev_info_t *); +extern void	pm_unrecord_threshold(char *); +extern int	pm_S3_enabled; +extern int	pm_ppm_searchlist(pm_searchargs_t *); +extern psce_t	*pm_psc_clone_to_direct(int); +extern psce_t	*pm_psc_clone_to_interest(int);  /*   * The soft state of the power manager.  Since there will only @@ -181,7 +196,7 @@ pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  		pmstp->pm_instance = ddi_get_instance(dip);  		if (ddi_create_minor_node(dip, "pm", S_IFCHR,  		    (pmstp->pm_instance << 8) + 0, -			DDI_PSEUDO, 0) != DDI_SUCCESS) { +		    DDI_PSEUDO, 0) != DDI_SUCCESS) {  			return (DDI_FAILURE);  		}  		pmstp->pm_dip = dip;	/* pm_init and getinfo depend on it */ @@ -271,6 +286,7 @@ pm_close_direct_pm_device(dev_info_t *dip, void *arg)  #define	NODEP		5  #define	DEP		6  #define	PM_PSC		7 +#define	PM_SRCH		8  #define	CHECKPERMS	0x001  #define	SU		0x002 @@ -405,6 +421,8 @@ static struct pm_cmd_info pmci[] = {  	{PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ,  	    INWHO, DIP, NODEP, SU},  	{PM_GET_PM_STATE, "PM_GET_PM_STATE", 1, NOSTRUCT}, +	{PM_GET_AUTOS3_STATE, "PM_GET_AUTOS3_STATE", 1, NOSTRUCT}, +	{PM_GET_S3_SUPPORT_STATE, "PM_GET_S3_SUPPORT_STATE", 1, NOSTRUCT},  	{PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", 1, PM_REQ, INWHO,  	    DIP, NODEP},  	{PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ, @@ -431,6 +449,14 @@ static struct pm_cmd_info pmci[] = {  	{PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT,  	    0, 0, 0, SU},  	{PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", 1, NOSTRUCT}, +	{PM_START_AUTOS3, "PM_START_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU}, +	{PM_STOP_AUTOS3, "PM_STOP_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU}, +	{PM_ENABLE_S3, "PM_ENABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU}, +	{PM_DISABLE_S3, "PM_DISABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU}, +	{PM_ENTER_S3, "PM_ENTER_S3", 1, NOSTRUCT, 0, 0, 0, SU}, +	{PM_SEARCH_LIST, "PM_SEARCH_LIST", 1, PM_SRCH, 0, 0, 0, SU}, +	{PM_GET_CMD_NAME, "PM_GET_CMD_NAME", 1, PM_REQ, INDATAOUT, NODIP, +	    NODEP, 0},  	{0, NULL}  }; @@ -729,8 +755,6 @@ static void  pm_discard_entries(int clone)  {  	psce_t	*pscep; -	psce_t			*pm_psc_clone_to_direct(int); -	psce_t			*pm_psc_clone_to_interest(int);  	int			direct = 0;  	mutex_enter(&pm_clone_lock); @@ -901,26 +925,21 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  	size_t		wholen;			/* copyinstr length */  	size_t		deplen = MAXNAMELEN;  	char		*dep, i_dep_buf[MAXNAMELEN]; -	char		*pathbuf; +	char		pathbuf[MAXNAMELEN];  	struct pm_component *cp;  #ifdef	_MULTI_DATAMODEL  	pm_state_change32_t		*pscp32;  	pm_state_change32_t		psc32; +	pm_searchargs32_t		psa32;  	size_t				copysize32;  #endif  	pm_state_change_t		*pscp;  	pm_state_change_t		psc; +	pm_searchargs_t		psa; +	char		listname[MAXCOPYBUF]; +	char		manufacturer[MAXCOPYBUF]; +	char		product[MAXCOPYBUF];  	size_t		copysize; -	extern void	pm_record_thresh(pm_thresh_rec_t *); -	psce_t		*pm_psc_clone_to_direct(int); -	psce_t		*pm_psc_clone_to_interest(int); -	extern	void	pm_register_watcher(int, dev_info_t *); -	extern	int	pm_get_current_power(dev_info_t *, int, int *); -	extern	int	pm_interest_registered(int); -	extern	void	pm_all_to_default_thresholds(void); -	extern	int	pm_current_threshold(dev_info_t *, int, int *); -	extern void	pm_deregister_watcher(int, dev_info_t *); -	extern void	pm_unrecord_threshold(char *);  	PMD(PMD_IOCTL, ("ioctl: %s: begin\n", cmdstr)) @@ -955,6 +974,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  	}  	switch (pcip->str_type) {  	case PM_REQ: +	{  #ifdef	_MULTI_DATAMODEL  		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {  			pm_req32_t	req32; @@ -979,9 +999,9 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  					break;  				}  				req.physpath = who; +				PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", +				    cmdstr, req.physpath))  			} -			PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr, -			    req.physpath))  			if (pcip->inargs & INDATA) {  				req.data = (void *)(uintptr_t)req32.data;  				req.datasize = req32.datasize; @@ -1053,9 +1073,8 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				ASSERT(!(pcip->inargs & INDATAINT));  				ASSERT(pcip->deptype == DEP);  				if (req32.data != NULL) { -					size_t dummy;  					if (copyinstr((void *)(uintptr_t) -					    req32.data, dep, deplen, &dummy)) { +					    req32.data, dep, deplen, NULL)) {  						PMD(PMD_ERROR, ("ioctl: %s: "  						    "0x%p dep size %lx, EFAULT"  						    "\n", cmdstr, @@ -1096,9 +1115,9 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  					break;  				}  				req.physpath = who; +				PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", +				    cmdstr, req.physpath))  			} -			PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr, -			    req.physpath))  			if (!(pcip->inargs & INDATA)) {  				req.data = NULL;  				req.datasize = 0; @@ -1154,9 +1173,8 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				ASSERT(!(pcip->inargs & INDATAINT));  				ASSERT(pcip->deptype == DEP);  				if (req.data != NULL) { -					size_t dummy;  					if (copyinstr((caddr_t)req.data, -					    dep, deplen, &dummy)) { +					    dep, deplen, NULL)) {  						PMD(PMD_ERROR, ("ioctl: %s: "  						    "0x%p dep size %lu, "  						    "EFAULT\n", cmdstr, @@ -1222,6 +1240,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  		}  		case PM_GET_DEVICE_THRESHOLD: +		{  			PM_LOCK_DIP(dip);  			if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) {  				PM_UNLOCK_DIP(dip); @@ -1234,6 +1253,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			PM_UNLOCK_DIP(dip);  			ret = 0;  			break; +		}  		case PM_DIRECT_PM:  		{ @@ -1248,11 +1268,9 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			 * Check to see if we are there is a dependency on  			 * this kept device, if so, return EBUSY.  			 */ -			pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);  			(void) ddi_pathname(dip, pathbuf);  			pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT,  			    NULL, pathbuf, PM_DEP_WAIT, &has_dep, 0); -			kmem_free(pathbuf, MAXPATHLEN);  			if (has_dep) {  				PMD(PMD_ERROR | PMD_DPM, ("%s EBUSY\n",  				    cmdstr)) @@ -1301,11 +1319,9 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			info->pmi_dev_pm_state &= ~PM_DIRECT;  			PM_UNLOCK_DIP(dip);  			/* Bring ourselves up if there is a keeper. */ -			pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);  			(void) ddi_pathname(dip, pathbuf);  			pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF,  			    NULL, pathbuf, PM_DEP_WAIT, NULL, 0); -			kmem_free(pathbuf, MAXPATHLEN);  			pm_discard_entries(clone);  			pm_deregister_watcher(clone, dip);  			/* @@ -1426,6 +1442,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  		}  		case PM_GET_CURRENT_POWER: +		{  			if (pm_get_current_power(dip, req.component,  			    rval_p) != DDI_SUCCESS) {  				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s " @@ -1440,6 +1457,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			else  				ret = 0;  			break; +		}  		case PM_GET_TIME_IDLE:  		{ @@ -1629,11 +1647,14 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  		}  		case PM_GET_NUM_COMPONENTS: +		{  			ret = 0;  			*rval_p = PM_NUMCMPTS(dip);  			break; +		}  		case PM_GET_DEVICE_TYPE: +		{  			ret = 0;  			if ((info = PM_GET_PM_INFO(dip)) == NULL) {  				PMD(PMD_ERROR, ("ioctl: %s: " @@ -1647,6 +1668,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				*rval_p = PM_AUTOPM;  			}  			break; +		}  		case PM_SET_COMPONENT_THRESHOLDS:  		{ @@ -1981,6 +2003,8 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  					    cmdstr, PM_DEVICE(dip),  					    (void *)req.data))  					ASSERT(!dipheld); +					kmem_free(timestamp, +					    comps * sizeof (time_t));  					return (EFAULT);  				}  				rvaddr = (caddr_t)req.data; @@ -1994,7 +2018,24 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			break;  		} +		case PM_GET_CMD_NAME: +		{ +			PMD(PMD_IOCTL, ("%s: %s\n", cmdstr, +			    pm_decode_cmd(req.value))) +			if (ret = copyoutstr(pm_decode_cmd(req.value), +			    (char *)req.data, req.datasize, &lencopied)) { +				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " +				    "copyoutstr %p failed--EFAULT\n", cmdstr, +				    PM_DEVICE(dip), (void *)req.data)) +				break; +			} +			*rval_p = lencopied; +			ret = 0; +			break; +		} +  		case PM_GET_COMPONENT_NAME: +		{  			ASSERT(dip);  			if (!e_pm_valid_comp(dip, req.component, &cp)) {  				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " @@ -2014,6 +2055,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			*rval_p = lencopied;  			ret = 0;  			break; +		}  		case PM_GET_POWER_NAME:  		{ @@ -2118,6 +2160,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  		case PM_GET_NUM_POWER_LEVELS: +		{  			if (!e_pm_valid_comp(dip, req.component, &cp)) {  				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "  				    "component %d > numcmpts - 1 %d--EINVAL\n", @@ -2129,8 +2172,10 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			*rval_p = cp->pmc_comp.pmc_numlevels;  			ret = 0;  			break; +		}  		case PM_GET_DEVICE_THRESHOLD_BASIS: +		{  			ret = 0;  			PM_LOCK_DIP(dip);  			if ((info = PM_GET_PM_INFO(dip)) == NULL) { @@ -2172,9 +2217,23 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			PM_UNLOCK_DIP(dip);  			break;  		} +		default: +			/* +			 * Internal error, invalid ioctl description +			 * force debug entry even if pm_debug not set +			 */ +#ifdef	DEBUG +			pm_log("invalid diptype %d for cmd %d (%s)\n", +			    pcip->diptype, cmd, pcip->name); +#endif +			ASSERT(0); +			return (EIO); +		}  		break; +	}  	case PM_PSC: +	{  		/*  		 * Commands that require pm_state_change_t as arg  		 */ @@ -2461,7 +2520,7 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {  				if (ddi_copyout(&psc32.component,  				    &pscp32->component, copysize32, mode) -					!= 0) { +				    != 0) {  					PMD(PMD_ERROR, ("ioctl: %s: copyout "  					    "failed--EFAULT\n", cmdstr))  					ret = EFAULT; @@ -2482,14 +2541,128 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			break;  		}  		default: +			/* +			 * Internal error, invalid ioctl description +			 * force debug entry even if pm_debug not set +			 */ +#ifdef	DEBUG +			pm_log("invalid diptype %d for cmd %d (%s)\n", +			    pcip->diptype, cmd, pcip->name); +#endif  			ASSERT(0); +			return (EIO);  		}  		break; +	} + +	case PM_SRCH:		/* command that takes a pm_searchargs_t arg */ +	{ +		/* +		 * If no ppm, then there is nothing to search. +		 */ +		if (DEVI(ddi_root_node())->devi_pm_ppm == NULL) { +			ret = ENODEV; +			break; +		} + +#ifdef	_MULTI_DATAMODEL +		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { +			if (ddi_copyin((caddr_t)arg, &psa32, +			    sizeof (psa32), mode) != 0) { +				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " +				    "EFAULT\n\n", cmdstr)) +				return (EFAULT); +			} +			if (copyinstr((void *)(uintptr_t)psa32.pms_listname, +			    listname, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)(uintptr_t)psa32.pms_listname, +				    MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +			if (copyinstr((void *)(uintptr_t)psa32.pms_manufacturer, +			    manufacturer, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)(uintptr_t)psa32.pms_manufacturer, +				    MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +			if (copyinstr((void *)(uintptr_t)psa32.pms_product, +			    product, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)(uintptr_t)psa32.pms_product, +				    MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +		} else +#endif /* _MULTI_DATAMODEL */ +		{ +			if (ddi_copyin((caddr_t)arg, &psa, +			    sizeof (psa), mode) != 0) { +				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " +				    "EFAULT\n\n", cmdstr)) +				return (EFAULT); +			} +			if (copyinstr(psa.pms_listname, +			    listname, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)psa.pms_listname, MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +			if (copyinstr(psa.pms_manufacturer, +			    manufacturer, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)psa.pms_manufacturer, MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +			if (copyinstr(psa.pms_product, +			    product, MAXCOPYBUF, NULL)) { +				PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " +				    "%d, " "EFAULT\n", cmdstr, +				    (void *)psa.pms_product, MAXCOPYBUF)) +				ret = EFAULT; +				break; +			} +		} +		psa.pms_listname = listname; +		psa.pms_manufacturer = manufacturer; +		psa.pms_product = product; +		switch (cmd) { +		case PM_SEARCH_LIST: +			ret = pm_ppm_searchlist(&psa); +			break; + +		default: +			/* +			 * Internal error, invalid ioctl description +			 * force debug entry even if pm_debug not set +			 */ +#ifdef	DEBUG +			pm_log("invalid diptype %d for cmd %d (%s)\n", +			    pcip->diptype, cmd, pcip->name); +#endif +			ASSERT(0); +			return (EIO); +		} +		break; +	}  	case NOSTRUCT: +	{  		switch (cmd) {  		case PM_START_PM:  		case PM_START_CPUPM: +		{  			mutex_enter(&pm_scan_lock);  			if ((cmd == PM_START_PM && autopm_enabled) ||  			    (cmd == PM_START_CPUPM && PM_CPUPM_ENABLED)) { @@ -2500,13 +2673,14 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				break;  			}  			if (cmd == PM_START_PM) -			    autopm_enabled = 1; +				autopm_enabled = 1;  			else -			    cpupm = PM_CPUPM_ENABLE; +				cpupm = PM_CPUPM_ENABLE;  			mutex_exit(&pm_scan_lock);  			ddi_walk_devs(ddi_root_node(), pm_start_pm_walk, &cmd);  			ret = 0;  			break; +		}  		case PM_RESET_PM:  		case PM_STOP_PM: @@ -2523,13 +2697,16 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				ret = EINVAL;  				break;  			} -			if (cmd == PM_STOP_PM) -			    autopm_enabled = 0; -			else if (cmd == PM_STOP_CPUPM) -			    cpupm = PM_CPUPM_DISABLE; -			else { -			    autopm_enabled = 0; -			    cpupm = PM_CPUPM_NOTSET; +			if (cmd == PM_STOP_PM) { +				autopm_enabled = 0; +				pm_S3_enabled = 0; +				autoS3_enabled = 0; +			} else if (cmd == PM_STOP_CPUPM) { +				cpupm = PM_CPUPM_DISABLE; +			} else { +				autopm_enabled = 0; +				autoS3_enabled = 0; +				cpupm = PM_CPUPM_NOTSET;  			}  			mutex_exit(&pm_scan_lock); @@ -2553,22 +2730,29 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  		}  		case PM_GET_SYSTEM_THRESHOLD: +		{  			*rval_p = pm_system_idle_threshold;  			ret = 0;  			break; +		}  		case PM_GET_DEFAULT_SYSTEM_THRESHOLD: +		{  			*rval_p = pm_default_idle_threshold;  			ret = 0;  			break; +		}  		case PM_GET_CPU_THRESHOLD: +		{  			*rval_p = pm_cpu_idle_threshold;  			ret = 0;  			break; +		}  		case PM_SET_SYSTEM_THRESHOLD:  		case PM_SET_CPU_THRESHOLD: +		{  			if ((int)arg < 0) {  				PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0"  				    "--EINVAL\n", cmdstr, (int)arg)) @@ -2583,20 +2767,24 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  				pm_cpu_idle_threshold = (int)arg;  			}  			ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk, -				    (void *) &cmd); +			    (void *) &cmd);  			ret = 0;  			break; +		}  		case PM_IDLE_DOWN: +		{  			if (pm_timeout_idledown() != 0) {  				ddi_walk_devs(ddi_root_node(),  				    pm_start_idledown, (void *)PMID_IOC);  			}  			ret = 0;  			break; +		}  		case PM_GET_PM_STATE: +		{  			if (autopm_enabled) {  				*rval_p = PM_SYSTEM_PM_ENABLED;  			} else { @@ -2604,8 +2792,10 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			}  			ret = 0;  			break; +		}  		case PM_GET_CPUPM_STATE: +		{  			if (PM_CPUPM_ENABLED)  				*rval_p = PM_CPU_PM_ENABLED;  			else if (PM_CPUPM_DISABLED) @@ -2615,7 +2805,96 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)  			ret = 0;  			break;  		} + +		case PM_GET_AUTOS3_STATE: +		{ +			if (autoS3_enabled) { +				*rval_p = PM_AUTOS3_ENABLED; +			} else { +				*rval_p = PM_AUTOS3_DISABLED; +			} +			ret = 0; +			break; +		} + +		case PM_GET_S3_SUPPORT_STATE: +		{ +			if (pm_S3_enabled) { +				*rval_p = PM_S3_SUPPORT_ENABLED; +			} else { +				*rval_p = PM_S3_SUPPORT_DISABLED; +			} +			ret = 0; +			break; +		} + +		/* +		 * pmconfig tells us if the platform supports S3 +		 */ +		case PM_ENABLE_S3: +		{ +			mutex_enter(&pm_scan_lock); +			if (pm_S3_enabled) { +				mutex_exit(&pm_scan_lock); +				PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", +				    cmdstr)) +				ret = EBUSY; +				break; +			} +			pm_S3_enabled = 1; +			mutex_exit(&pm_scan_lock); +			ret = 0; +			break; +		} + +		case PM_DISABLE_S3: +		{ +			mutex_enter(&pm_scan_lock); +			pm_S3_enabled = 0; +			mutex_exit(&pm_scan_lock); +			ret = 0; +			break; +		} + +		case PM_START_AUTOS3: +		{ +			mutex_enter(&pm_scan_lock); +			if (autoS3_enabled) { +				mutex_exit(&pm_scan_lock); +				PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", +				    cmdstr)) +				ret = EBUSY; +				break; +			} +			autoS3_enabled = 1; +			mutex_exit(&pm_scan_lock); +			ret = 0; +			break; +		} + +		case PM_STOP_AUTOS3: +		{ +			mutex_enter(&pm_scan_lock); +			autoS3_enabled = 0; +			mutex_exit(&pm_scan_lock); +			ret = 0; +			break; +		} + +		default: +			/* +			 * Internal error, invalid ioctl description +			 * force debug entry even if pm_debug not set +			 */ +#ifdef	DEBUG +			pm_log("invalid diptype %d for cmd %d (%s)\n", +			    pcip->diptype, cmd, pcip->name); +#endif +			ASSERT(0); +			return (EIO); +		}  		break; +	}  	default:  		/* diff --git a/usr/src/uts/common/io/ppm/ppm.c b/usr/src/uts/common/io/ppm/ppm.c index b35a2e369d..e52ff63b78 100644 --- a/usr/src/uts/common/io/ppm/ppm.c +++ b/usr/src/uts/common/io/ppm/ppm.c @@ -206,8 +206,10 @@ int  _init(void)  {  	if (ddi_soft_state_init( -	    &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) +	    &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) { +		PPMD(D_INIT, ("ppm: soft state init\n"))  		return (DDI_FAILURE); +	}  	if (mod_install(&modlinkage) != DDI_SUCCESS) {  		ddi_soft_state_fini(&ppm_statep); @@ -220,7 +222,12 @@ _init(void)  int  _fini(void)  { -	return (mod_remove(&modlinkage)); +	int error; + +	if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) +		ddi_soft_state_fini(&ppm_statep); + +	return (error);  } @@ -679,7 +686,7 @@ err_bydom:  		STRUCT_INIT(norm, mode);  		ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(norm), -		STRUCT_SIZE(norm), mode); +		    STRUCT_SIZE(norm), mode);  		if (ret != 0)  			return (EFAULT); @@ -755,6 +762,10 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,  	ppm_owned_t	*owned;  	int		mode;  	int		ret = DDI_SUCCESS; +	static int	ppm_manage_sx(s3a_t *, int); +	static int	ppm_search_list(pm_searchargs_t *); +	int 		*res = (int *)result; +	s3a_t s3args;  #ifdef DEBUG  	char	*str = "ppm_ctlops"; @@ -765,8 +776,9 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,  		    str, ddi_binding_name(rdip), ctlstr))  #endif -	if (ctlop != DDI_CTLOPS_POWER) +	if (ctlop != DDI_CTLOPS_POWER) {  		return (DDI_FAILURE); +	}  	unitp = (ppm_unit_t *)ddi_get_soft_state(ppm_statep, ppm_inst); @@ -779,8 +791,6 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,  			ppm_manage_led(PPM_LED_BLINKING);  		else  			ppm_manage_led(PPM_LED_SOLIDON); -		PPMD(D_LOWEST, ("%s: %sall devices are at lowest power \n", -		    str, mode ? "" : "not "))  		return (DDI_SUCCESS);  	/* undo the claiming of 'rdip' at attach time */ @@ -984,9 +994,37 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip,  			return (DDI_FAILURE);  		} +	case PMR_PPM_ENTER_SX: +	case PMR_PPM_EXIT_SX: +		s3args.s3a_state = reqp->req.ppm_power_enter_sx_req.sx_state; +		s3args.s3a_test_point = +		    reqp->req.ppm_power_enter_sx_req.test_point; +		s3args.s3a_wakephys = reqp->req.ppm_power_enter_sx_req.wakephys; +		s3args.s3a_psr = reqp->req.ppm_power_enter_sx_req.psr; +		ret = ppm_manage_sx(&s3args, +		    reqp->request_type == PMR_PPM_ENTER_SX); +		if (ret) { +			PPMD(D_CPR, ("ppm_manage_sx returns %d\n", ret)) +			return (DDI_FAILURE); +		} else { +			return (DDI_SUCCESS); +		} + +	case PMR_PPM_SEARCH_LIST: +		ret = ppm_search_list(reqp->req.ppm_search_list_req.searchlist); +		reqp->req.ppm_search_list_req.result = ret; +		*res = ret; +		if (ret) { +			PPMD(D_CPR, ("ppm_search_list returns %d\n", ret)) +			return (DDI_FAILURE); +		} else { +			PPMD(D_CPR, ("ppm_search_list returns %d\n", ret)) +			return (DDI_SUCCESS); +		} +  	default:  		cmn_err(CE_WARN, "ppm_ctlops: unrecognized ctlops req(%d)", -			reqp->request_type); +		    reqp->request_type);  		return (DDI_FAILURE);  	}  } @@ -1246,7 +1284,7 @@ ppm_bringup_domains()  		}  		mutex_exit(&domp->lock);  	} -	PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmbringup, ret)) +	PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmbringup))  	return (ret);  } @@ -1275,6 +1313,15 @@ ppm_sync_bookkeeping()  			mutex_exit(&domp->lock);  			continue;  		} + +		/* +		 * skip NULL .devlist slot, for some may host pci device +		 * that can not tolerate clock off or not even participate +		 * in PM. +		 */ +		if (domp->devlist == NULL) +			continue; +  		switch (domp->model) {  		case PPMD_FET:  			ret = ppm_fetset(domp, PPMD_OFF); @@ -1291,7 +1338,7 @@ ppm_sync_bookkeeping()  		}  		mutex_exit(&domp->lock);  	} -	PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmsyncbp, ret)) +	PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmsyncbp))  	return (ret);  } @@ -1655,14 +1702,14 @@ ppm_fetset(ppm_domain_t *domp, uint8_t value)  				 * we might wait for longer than required  				 */  				PPMD(D_FET, ("%s : waiting %lu micro seconds " -					"before on\n", domp->name, -					delay - temp)) +				    "before on\n", domp->name, +				    delay - temp));  				drv_usecwait(delay - temp);  			}  		}  	}  	switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u  	case PPMDC_I2CKIO: {  		i2c_gpio_t i2c_req;  		i2c_req.reg_mask = dc->m_un.i2c.mask; @@ -1739,7 +1786,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl)  	}  	switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u  	case PPMDC_I2CKIO: {  		i2c_gpio_t i2c_req;  		i2c_req.reg_mask = dc->m_un.i2c.mask; @@ -1773,7 +1820,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl)  		}  		off_val = (dc->cmd == PPMDC_FET_OFF) ? dc->m_un.kio.val : -			dc->next->m_un.kio.val; +		    dc->next->m_un.kio.val;  		*lvl = (kio_val == off_val) ? PPMD_OFF : PPMD_ON;  		PPMD(D_FET, ("%s: %s domain FET %s\n", str, domp->name, @@ -2187,7 +2234,7 @@ ppm_gpioset(ppm_domain_t *domp, int key)  	}  	switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u  	case PPMDC_I2CKIO: {  		i2c_gpio_t i2c_req;  		ppm_dev_t *pdev; @@ -2223,6 +2270,7 @@ ppm_gpioset(ppm_domain_t *domp, int key)  		break;  	}  #endif +  	case PPMDC_KIO:  		ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr,  		    (intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, kcred, @@ -2666,3 +2714,100 @@ ppm_power_down_domain(dev_info_t *dip)  	mutex_exit(&domp->lock);  	return (ret);  } + +static int +ppm_manage_sx(s3a_t *s3ap, int enter) +{ +	ppm_domain_t *domp = ppm_lookup_domain("domain_estar"); +	ppm_dc_t *dc; +	int ret = 0; + +	if (domp == NULL) { +		PPMD(D_CPR, ("ppm_manage_sx: can't find estar domain\n")) +		return (ENODEV); +	} +	PPMD(D_CPR, ("ppm_manage_sx %x, enter %d\n", s3ap->s3a_state, +	    enter)) +	switch (s3ap->s3a_state) { +	case S3: +		if (enter) { +			dc = ppm_lookup_dc(domp, PPMDC_ENTER_S3); +		} else { +			dc = ppm_lookup_dc(domp, PPMDC_EXIT_S3); +		} +		ASSERT(dc && dc->method == PPMDC_KIO); +		PPMD(D_CPR, +		    ("ppm_manage_sx: calling acpi driver (handle %p)" +		    " with %x\n", (void *)dc->lh, dc->m_un.kio.iowr)) +		ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, +		    (intptr_t)s3ap, FWRITE | FKIOCTL, kcred, NULL); +		break; + +	case S4: +		/* S4 is not supported yet */ +		return (EINVAL); +	default: +		ASSERT(0); +	} +	return (ret); +} + +/* + * Search enable/disable lists, which are encoded in ppm.conf as an array + * of char strings. + */ +static int +ppm_search_list(pm_searchargs_t *sl) +{ +	int i; +	int flags = DDI_PROP_DONTPASS; +	ppm_unit_t *unitp = ddi_get_soft_state(ppm_statep, ppm_inst); +	char **pp; +	char *starp; +	uint_t nelements; +	char *manuf = sl->pms_manufacturer; +	char *prod = sl->pms_product; + +	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, unitp->dip, flags, +	    sl->pms_listname, &pp, &nelements) != DDI_PROP_SUCCESS) { +		PPMD(D_CPR, ("ppm_search_list prop lookup %s failed--EINVAL\n", +		    sl->pms_listname)) +		return (EINVAL); +	} +	ASSERT((nelements & 1) == 0);		/* must be even */ + +	PPMD(D_CPR, ("ppm_search_list looking for %s, %s\n", manuf, prod)) + +	for (i = 0; i < nelements; i += 2) { +		PPMD(D_CPR, ("checking %s, %s", pp[i], pp[i+1])) +		/* we support only a trailing '*' pattern match */ +		if ((starp = strchr(pp[i], '*')) != NULL && *(starp + 1) == 0) { +			/* LINTED - ptrdiff overflow */ +			if (strncmp(manuf, pp[i], (starp - pp[i])) != 0) { +				PPMD(D_CPR, (" no match %s with %s\n", +				    manuf, pp[i + 1])) +				continue; +			} +		} +		if ((starp = strchr(pp[i + 1], '*')) != NULL && +		    *(starp + 1) == 0) { +			if (strncmp(prod, +			    /* LINTED - ptrdiff overflow */ +			    pp[i + 1], (starp - pp[i + 1])) != 0) { +				PPMD(D_CPR, (" no match %s with %s\n", +				    prod, pp[i + 1])) +				continue; +			} +		} +		if (strcmp(manuf, pp[i]) == 0 && +		    (strcmp(prod, pp[i + 1]) == 0)) { +			PPMD(D_CPR, (" match\n")) +			ddi_prop_free(pp); +			return (0); +		} +		PPMD(D_CPR, (" no match %s with %s or %s with %s\n", +		    manuf, pp[i], prod, pp[i + 1])) +	} +	ddi_prop_free(pp); +	return (ENODEV); +} diff --git a/usr/src/uts/common/io/ppm/ppm_subr.c b/usr/src/uts/common/io/ppm/ppm_subr.c index 4bcd24c877..617ac3a380 100644 --- a/usr/src/uts/common/io/ppm/ppm_subr.c +++ b/usr/src/uts/common/io/ppm/ppm_subr.c @@ -207,6 +207,7 @@ ppm_lookup_hndl(int model, ppm_dc_t *key_dc)  #define	PPM_CTRL_PROP_SUFFIX		"-control"  struct ppm_domit ppm_domit_data[] = { +	"SX",  PPMD_SX, 0, PPMD_ON,  	"CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,  	"FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,  	"PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON, @@ -401,11 +402,19 @@ ppm_lookup_dev(dev_info_t *dip)  	PPM_GET_PATHNAME(dip, path);  	for (domp = ppm_domain_p; domp; domp = domp->next) { -		if (PPM_DOMAIN_UP(domp)) +		if (PPM_DOMAIN_UP(domp)) {  			for (dbp = domp->conflist; dbp; dbp = dbp->next) { +				/* +				 * allow claiming root without knowing +				 * its full name +				 */ +				if (dip == ddi_root_node() && +				    strcmp(dbp->name, "/") == 0) +					return (domp);  				if (ppm_match_devs(path, dbp) == 0)  					return (domp);  			} +		}  	}  	return (NULL); @@ -514,7 +523,8 @@ ppm_match_devs(char *dev_path, ppm_db_t *dbp)  	/* "<exact match>*"	*/  	if (dbp->name[dbp->wcpos[0] + 1] == 0) {  		cp = path + dbp->wcpos[0]; -		while (*cp && (*cp++ != '/')); +		while (*cp && (*cp++ != '/')) +			;  		return ((*cp == 0) ? 0 : -1);  	} @@ -761,6 +771,22 @@ ppm_init_cb(dev_info_t *dip)  	for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {  		for (dc = domp->dc; dc; dc = dc->next) { +			/* +			 * Warning: This code is rather confusing. +			 * +			 * It intends to ensure that ppm_init_lyr() is only +			 * called ONCE for a device that may be associated +			 * with more than one domain control. +			 * So, what it does is first to check to see if +			 * there is a handle, and then if not it goes on +			 * to call the init_lyr() routine. +			 * +			 * The non-obvious thing is that the ppm_init_lyr() +			 * routine, in addition to opening the device +			 * associated with the dc (domain control) in +			 * question, has the side-effect of creating the +			 * handle for that dc as well. +			 */  			if (ppm_lookup_hndl(domp->model, dc) != NULL)  				continue; @@ -979,6 +1005,8 @@ struct ppm_confdefs {  	char	*sym;  	int	val;  } ppm_confdefs_table[] = { +	"ENTER_S3", PPMDC_ENTER_S3, +	"EXIT_S3", PPMDC_EXIT_S3,  	"CPU_NEXT", PPMDC_CPU_NEXT,  	"PRE_CHNG", PPMDC_PRE_CHNG,  	"CPU_GO", PPMDC_CPU_GO, @@ -991,7 +1019,9 @@ struct ppm_confdefs {  	"LED_OFF", PPMDC_LED_OFF,  	"KIO", PPMDC_KIO,  	"VCORE", PPMDC_VCORE, +#ifdef sun4u  	"I2CKIO", PPMDC_I2CKIO, +#endif  	"CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,  	"PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,  	"PRE_PWR_ON", PPMDC_PRE_PWR_ON, @@ -1103,14 +1133,20 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)  			(void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);  			continue;  		} +#ifdef sun4u  		if (strstr(dclist[i], "mask=")) {  			(void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);  			continue;  		} +#endif  		/* This must be before the if statement for delay */  		if (strstr(dclist[i], "post_delay=")) { +#ifdef sun4u  			ASSERT(dc->method == PPMDC_KIO ||  			    dc->method == PPMDC_I2CKIO); +#else +			ASSERT(dc->method == PPMDC_KIO); +#endif  			/*  			 * all delays are uint_t type instead of clock_t.  			 * If the delay is too long, it might get truncated. @@ -1119,13 +1155,15 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)  			switch (dc->method) {  			case PPMDC_KIO:  				(void) ppm_stoi(dclist[i], -					    &dc->m_un.kio.post_delay); +				    &dc->m_un.kio.post_delay);  				break; +#ifdef sun4u  			case PPMDC_I2CKIO:  				(void) ppm_stoi(dclist[i], -					    &dc->m_un.i2c.post_delay); +				    &dc->m_un.i2c.post_delay);  				break; +#endif  			default:  				break; @@ -1133,9 +1171,14 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)  			continue;  		}  		if (strstr(dclist[i], "delay=")) { +#ifdef sun4u +			ASSERT(dc->method == PPMDC_VCORE || +			    dc->method == PPMDC_KIO || +			    dc->method == PPMDC_I2CKIO); +#else  			ASSERT(dc->method == PPMDC_VCORE || -				dc->method == PPMDC_KIO || -				dc->method == PPMDC_I2CKIO); +			    dc->method == PPMDC_KIO); +#endif  			/*  			 * all delays are uint_t type instead of clock_t. @@ -1148,9 +1191,11 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)  				(void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);  				break; +#ifdef sun4u  			case PPMDC_I2CKIO:  				(void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);  				break; +#endif  			case PPMDC_VCORE:  				(void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay); @@ -1227,6 +1272,8 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd)  	case PPMDC_PWR_ON:  	case PPMDC_RESET_OFF:  	case PPMDC_RESET_ON: +	case PPMDC_ENTER_S3: +	case PPMDC_EXIT_S3:  		break;  	default:  		PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd)) @@ -1234,9 +1281,11 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd)  	}  	for (dc = domp->dc; dc; dc = dc->next) { -		if (dc->cmd == cmd) +		if (dc->cmd == cmd) {  			return (dc); +		}  	} +  	return (NULL);  } @@ -1315,6 +1364,7 @@ ppm_get_ctlstr(int ctlop, uint_t mask)  		FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),  		FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),  		FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER), +		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),  		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),  	}; @@ -1334,13 +1384,15 @@ ppm_print_dc(ppm_dc_t *dc)  	PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n     cmd(%x), "  	    "method(%x), ", d->path, d->cmd, d->method)) -	if (d->method == PPMDC_I2CKIO) { +	if (d->method == PPMDC_KIO) { +		PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)", +		    d->m_un.kio.iowr, d->m_un.kio.val)) +#ifdef sun4u +	} else if (d->method == PPMDC_I2CKIO) {  		PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "  		    "i2c.mask(0x%X)", d->m_un.i2c.iowr,  		    d->m_un.i2c.val,  d->m_un.i2c.mask)) -	} else if (d->method == PPMDC_KIO) { -		PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)", -		    d->m_un.kio.iowr, d->m_un.kio.val)) +#endif  	} else if (d->method == PPMDC_VCORE) {  		PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "  		    ".delay(0x%x)", diff --git a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c index fa303ca9b5..f6d5870c5c 100644 --- a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c +++ b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c @@ -138,6 +138,7 @@ static void nv_read_signature(nv_port_t *nvp);  static void mcp55_set_intr(nv_port_t *nvp, int flag);  static void mcp04_set_intr(nv_port_t *nvp, int flag);  static void nv_resume(nv_port_t *nvp); +static void nv_suspend(nv_port_t *nvp);  static int nv_start_sync(nv_port_t *nvp, sata_pkt_t *spkt);  static int nv_abort_active(nv_port_t *nvp, sata_pkt_t *spkt, int abort_reason);  static void nv_copy_registers(nv_port_t *nvp, sata_device_t *sd, @@ -400,7 +401,7 @@ nv_get8(ddi_acc_handle_t handle, uint8_t *dev_addr)  static int  nv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  { -	int status, attach_state, intr_types, bar, i; +	int status, attach_state, intr_types, bar, i, command;  	int inst = ddi_get_instance(dip);  	ddi_acc_handle_t pci_conf_handle;  	nv_ctl_t *nvc; @@ -439,6 +440,20 @@ nv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  		attach_state |= ATTACH_PROGRESS_CONF_HANDLE; +		/* +		 * If a device is attached after a suspend/resume, sometimes +		 * the command register is zero, as it might not be set by +		 * BIOS or a parent.  Set it again here. +		 */ +		command = pci_config_get16(pci_conf_handle, PCI_CONF_COMM); + +		if (command == 0) { +			cmn_err(CE_WARN, "nv_sata%d: restoring PCI command" +			    " register", inst); +			pci_config_put16(pci_conf_handle, PCI_CONF_COMM, +			    PCI_COMM_IO|PCI_COMM_MAE|PCI_COMM_ME); +		} +  		subclass = pci_config_get8(pci_conf_handle, PCI_CONF_SUBCLASS);  		if (subclass & PCI_MASS_RAID) { @@ -585,7 +600,6 @@ nv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)  		NVLOG((NVDBG_INIT, nvc, NULL,  		    "nv_attach(): DDI_RESUME inst %d", inst)); -  		nvc->nvc_state &= ~NV_CTRL_SUSPEND;  		for (i = 0; i < NV_MAX_PORTS(nvc); i++) { @@ -716,6 +730,11 @@ nv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)  		 * the current state.  		 */  		NVLOG((NVDBG_INIT, nvc, NULL, "nv_detach: DDI_SUSPEND")); + +		for (i = 0; i < NV_MAX_PORTS(nvc); i++) { +			nv_suspend(&(nvc->nvc_port[i])); +		} +  		nvc->nvc_state |= NV_CTRL_SUSPEND;  		return (DDI_SUCCESS); @@ -1226,7 +1245,7 @@ nv_start_sync(nv_port_t *nvp, sata_pkt_t *spkt)  		(*(nvc->nvc_set_intr))(nvp, NV_INTR_ENABLE);  		NVLOG((NVDBG_SYNC, nvp->nvp_ctlp, nvp, "nv_sata_satapkt_sync:" -			" done % reason %d", ret)); +		    " done % reason %d", ret));  		return (ret);  	} @@ -2725,7 +2744,7 @@ mcp55_dma_setup_intr(nv_ctl_t *nvc, nv_port_t *nvp)  	    MCP_SATA_AE_NCQ_SDEV_DMA_SETUP_TAG_SHIFT};  	nv_cmn_err(CE_PANIC, nvc, nvp, -		"this is should not be executed at all until NCQ"); +	    "this is should not be executed at all until NCQ");  	mutex_enter(&nvp->nvp_mutex); @@ -4576,6 +4595,38 @@ nv_resume(nv_port_t *nvp)  	 * nv_reset(nvp);  	 */ +	nv_reset(nvp); + +	mutex_exit(&nvp->nvp_mutex); +} + +/* + * The PM functions for suspend and resume are incomplete and need additional + * work.  It may or may not work in the current state. + */ +static void +nv_suspend(nv_port_t *nvp) +{ +	NVLOG((NVDBG_INIT, nvp->nvp_ctlp, nvp, "nv_suspend()")); + +	mutex_enter(&nvp->nvp_mutex); + +	if (nvp->nvp_state & NV_PORT_INACTIVE) { +		mutex_exit(&nvp->nvp_mutex); + +		return; +	} + +	(*(nvp->nvp_ctlp->nvc_set_intr))(nvp, NV_INTR_DISABLE); + +	/* +	 * power may have been removed to the port and the +	 * drive, and/or a drive may have been added or removed. +	 * Force a reset which will cause a probe and re-establish +	 * any state needed on the drive. +	 * nv_reset(nvp); +	 */ +  	mutex_exit(&nvp->nvp_mutex);  } diff --git a/usr/src/uts/common/io/srn.c b/usr/src/uts/common/io/srn.c new file mode 100755 index 0000000000..cb2888871d --- /dev/null +++ b/usr/src/uts/common/io/srn.c @@ -0,0 +1,563 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2007 Sun Microsystems, Inc.  All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident	"%Z%%M%	%I%	%E% SMI" + +/* + * srn	Provide apm-like interfaces to Xorg + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/conf.h>		/* driver flags and functions */ +#include <sys/open.h>		/* OTYP_CHR definition */ +#include <sys/stat.h>		/* S_IFCHR definition */ +#include <sys/pathname.h>	/* name -> dev_info xlation */ +#include <sys/kmem.h>		/* memory alloc stuff */ +#include <sys/debug.h> +#include <sys/pm.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/epm.h> +#include <sys/vfs.h> +#include <sys/mode.h> +#include <sys/mkdev.h> +#include <sys/promif.h> +#include <sys/consdev.h> +#include <sys/ddi_impldefs.h> +#include <sys/poll.h> +#include <sys/note.h> +#include <sys/taskq.h> +#include <sys/policy.h> +#include <sys/srn.h> + +/* + * Minor number is instance<<8 + clone minor from range 1-255; + * But only one will be allocated + */ +#define	SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1)) +#define	SU		0x002 +#define	SG		0x004 + +extern kmutex_t	srn_clone_lock;	/* protects srn_clones array */ +extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; +extern uint_t	srn_poll_cnt[SRN_MAX_CLONE]; + +/* + * The soft state of the srn driver.  Since there will only be + * one of these, just reference it through a static struct. + */ +static struct srnstate { +	dev_info_t	*srn_dip;		/* ptr to our dev_info node */ +	int		srn_instance;		/* for ddi_get_instance() */ +	uchar_t		srn_clones[SRN_MAX_CLONE]; /* unique opens	*/ +	struct cred	*srn_cred[SRN_MAX_CLONE]; /* cred for each open	*/ +	int		srn_type[SRN_MAX_CLONE]; /* type of handshake */ +	int		srn_delivered[SRN_MAX_CLONE]; +	srn_event_info_t srn_pending[SRN_MAX_CLONE]; +} srn = { NULL, -1}; +typedef struct srnstate *srn_state_t; + +kcondvar_t	srn_clones_cv[SRN_MAX_CLONE]; +uint_t		srn_poll_cnt[SRN_MAX_CLONE];	/* count of events for poll */ +int		srn_apm_count; +int		srn_autosx_count; +struct pollhead	srn_pollhead[SRN_MAX_CLONE]; + +static int	srn_open(dev_t *, int, int, cred_t *); +static int	srn_close(dev_t, int, int, cred_t *); +static int	srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); +static int	srn_chpoll(dev_t, short, int, short *, struct pollhead **); + +static struct cb_ops srn_cb_ops = { +	srn_open,	/* open */ +	srn_close,	/* close */ +	nodev,		/* strategy */ +	nodev,		/* print */ +	nodev,		/* dump */ +	nodev,		/* read */ +	nodev,		/* write */ +	srn_ioctl,	/* ioctl */ +	nodev,		/* devmap */ +	nodev,		/* mmap */ +	nodev,		/* segmap */ +	srn_chpoll,	/* poll */ +	ddi_prop_op,	/* prop_op */ +	NULL,		/* streamtab */ +	D_NEW | D_MP	/* driver compatibility flag */ +}; + +static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, +    void **result); +static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static void srn_notify(int type, int event); + +static struct dev_ops srn_ops = { +	DEVO_REV,		/* devo_rev */ +	0,			/* refcnt */ +	srn_getinfo,		/* info */ +	nulldev,		/* identify */ +	nulldev,		/* probe */ +	srn_attach,		/* attach */ +	srn_detach,		/* detach */ +	nodev,			/* reset */ +	&srn_cb_ops,		/* driver operations */ +	NULL,			/* bus operations */ +	NULL			/* power */ +}; + +static struct modldrv modldrv = { +	&mod_driverops, +	"srn driver v1.4", +	&srn_ops +}; + +static struct modlinkage modlinkage = { +	MODREV_1, &modldrv, 0 +}; + +/* Local functions */ + +int +_init(void) +{ +	return (mod_install(&modlinkage)); +} + +int +_fini(void) +{ +	return (mod_remove(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ +	return (mod_info(&modlinkage, modinfop)); +} + +static int +srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ +	int		i; +	extern void (*srn_signal)(int, int); + +	switch (cmd) { + +	case DDI_ATTACH: +		if (srn.srn_instance != -1)	/* Only allow one instance */ +			return (DDI_FAILURE); +		srn.srn_instance = ddi_get_instance(dip); +		if (ddi_create_minor_node(dip, "srn", S_IFCHR, +		    (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0) +		    != DDI_SUCCESS) { +			return (DDI_FAILURE); +		} +		srn.srn_dip = dip;	/* srn_init and getinfo depend on it */ + +		for (i = 0; i < SRN_MAX_CLONE; i++) +			cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL); + +		srn.srn_instance = ddi_get_instance(dip); +		mutex_enter(&srn_clone_lock); +		srn_signal = srn_notify; +		mutex_exit(&srn_clone_lock); +		ddi_report_dev(dip); +		return (DDI_SUCCESS); + +	default: +		return (DDI_FAILURE); +	} +} + +/* ARGSUSED */ +static int +srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ +	int i; +	extern int srn_inuse; +	extern void (*srn_signal)(int, int); + +	switch (cmd) { +	case DDI_DETACH: + +		mutex_enter(&srn_clone_lock); +		while (srn_inuse) { +			mutex_exit(&srn_clone_lock); +			delay(1); +			mutex_enter(&srn_clone_lock); +		} +		srn_signal = NULL; +		mutex_exit(&srn_clone_lock); + +		for (i = 0; i < SRN_MAX_CLONE; i++) +			cv_destroy(&srn_clones_cv[i]); + +		ddi_remove_minor_node(dip, NULL); +		srn.srn_instance = -1; +		return (DDI_SUCCESS); + +	default: +		return (DDI_FAILURE); +	} +} + + +#ifdef DEBUG +char *srn_cmd_string; +int srn_cmd; +#endif + +/* + * Returns true if permission granted by credentials + * XXX + */ +static int +srn_perms(int perm, cred_t *cr) +{ +	if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ +		return (1); +	if ((perm & SG) && (crgetgid(cr) == 0))	/* group 0 is ok */ +		return (1); +	return (0); +} + +static int +srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, +	struct pollhead **phpp) +{ +	extern struct pollhead srn_pollhead[];	/* common/os/sunpm.c */ +	int	clone; + +	clone = SRN_MINOR_TO_CLONE(getminor(dev)); +	if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) { +		*reventsp |= (POLLIN | POLLRDNORM); +	} else { +		*reventsp = 0; +		if (!anyyet) { +			*phpp = &srn_pollhead[clone]; +		} +	} +	return (0); +} + +/*ARGSUSED*/ +static int +srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ +	dev_t	dev; +	int	instance; + +	switch (infocmd) { +	case DDI_INFO_DEVT2DEVINFO: +		if (srn.srn_instance == -1) +			return (DDI_FAILURE); +		*result = srn.srn_dip; +		return (DDI_SUCCESS); + +	case DDI_INFO_DEVT2INSTANCE: +		dev = (dev_t)arg; +		instance = getminor(dev) >> 8; +		*result = (void *)(uintptr_t)instance; +		return (DDI_SUCCESS); + +	default: +		return (DDI_FAILURE); +	} +} + + +/*ARGSUSED1*/ +static int +srn_open(dev_t *devp, int flag, int otyp, cred_t *cr) +{ +	int		clone; + +	if (otyp != OTYP_CHR) +		return (EINVAL); + +	mutex_enter(&srn_clone_lock); +	for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++) +		if (!srn.srn_clones[clone]) +			break; + +	if (clone == SRN_MAX_CLONE) { +		mutex_exit(&srn_clone_lock); +		return (ENXIO); +	} +	srn.srn_cred[clone] = cr; +	ASSERT(srn_apm_count >= 0); +	srn_apm_count++; +	srn.srn_type[clone] = SRN_TYPE_APM; +	crhold(cr); + +	*devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) + +	    clone); +	srn.srn_clones[clone] = 1; +	srn.srn_cred[clone] = cr; +	crhold(cr); +	mutex_exit(&srn_clone_lock); +	PMD(PMD_SX, ("srn open OK\n")) +	return (0); +} + +/*ARGSUSED1*/ +static int +srn_close(dev_t dev, int flag, int otyp, cred_t *cr) +{ +	int clone; + +	if (otyp != OTYP_CHR) +		return (EINVAL); + +	clone = SRN_MINOR_TO_CLONE(getminor(dev)); +	PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev), +	    clone)) +	mutex_enter(&srn_clone_lock); +	crfree(srn.srn_cred[clone]); +	srn.srn_cred[clone] = 0; +	srn_poll_cnt[clone] = 0; +	if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) { +		srn.srn_pending[clone].ae_type = 0; +		srn.srn_delivered[clone] = 0; +		cv_signal(&srn_clones_cv[clone]); +	} +	switch (srn.srn_type[clone]) { +	case SRN_TYPE_AUTOSX: +		ASSERT(srn_autosx_count); +		srn_autosx_count--; +		break; +	case SRN_TYPE_APM: +		ASSERT(srn_apm_count); +		srn_apm_count--; +		break; +	default: +		ASSERT(0); +		return (EINVAL); +	} +	srn.srn_clones[clone] = 0; +	mutex_exit(&srn_clone_lock); +	return (0); +} + +/*ARGSUSED*/ +static int +srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) +{ +	int clone = SRN_MINOR_TO_CLONE(getminor(dev)); + +	PMD(PMD_SX, ("ioctl: %x: begin\n", cmd)) + +	switch (cmd) { +	case SRN_IOC_NEXTEVENT: +	case SRN_IOC_SUSPEND: +	case SRN_IOC_RESUME: +	case SRN_IOC_AUTOSX: +		break; +	default: +		return (ENOTTY); +	} + +	if (!srn_perms(SU | SG, srn.srn_cred[clone])) { +		return (EPERM); +	} +	switch (cmd) { +	case SRN_IOC_AUTOSX: +		PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n")) +		mutex_enter(&srn_clone_lock); +		if (!srn.srn_clones[clone]) { +			PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n")) +			mutex_exit(&srn_clone_lock); +			return (EINVAL); +		} +		if (srn.srn_pending[clone].ae_type) { +			PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n")) +			mutex_exit(&srn_clone_lock); +			return (EBUSY); +		} +		if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) { +			PMD(PMD_SX, ("AUTOSX already--EBUSY\n")) +			mutex_exit(&srn_clone_lock); +			return (EBUSY); +		} +		ASSERT(srn.srn_type[clone] == SRN_TYPE_APM); +		srn.srn_type[clone] = SRN_TYPE_AUTOSX; +		srn_apm_count--; +		ASSERT(srn_apm_count >= 0); +		ASSERT(srn_autosx_count >= 0); +		srn_autosx_count++; +		mutex_exit(&srn_clone_lock); +		PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n")) +		return (0); + +	case SRN_IOC_NEXTEVENT: +		/* +		 * return the next suspend or resume event;  there should +		 * be one, cause we only get called if we've signalled a +		 * poll data completion +		 * then wake up the kernel thread sleeping for the delivery +		 */ +		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n")) +		mutex_enter(&srn_clone_lock); +		if (srn_poll_cnt[clone] == 0) { +			mutex_exit(&srn_clone_lock); +			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d " +			    "EWOULDBLOCK\n", clone)) +			return (EWOULDBLOCK); +		} +		ASSERT(srn.srn_pending[clone].ae_type); +		if (ddi_copyout(&srn.srn_pending[clone], (void *)arg, +		    sizeof (srn_event_info_t), mode) != 0) { +			mutex_exit(&srn_clone_lock); +			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n", +			    clone)) +			return (EFAULT); +		} +		if (srn.srn_type[clone] == SRN_TYPE_APM) +			srn.srn_delivered[clone] = +			    srn.srn_pending[clone].ae_type; +		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n", +		    clone, srn.srn_pending[clone].ae_type)) +		srn_poll_cnt[clone] = 0; +		mutex_exit(&srn_clone_lock); +		return (0); + +	case SRN_IOC_SUSPEND: +		/* ack suspend */ +		PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone)) +		mutex_enter(&srn_clone_lock); +		if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) { +			mutex_exit(&srn_clone_lock); +			PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n")) +			return (EINVAL); +		} +		srn.srn_delivered[clone] = 0; +		srn.srn_pending[clone].ae_type = 0; +		/* notify the kernel suspend thread  to continue */ +		PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone)) +		cv_signal(&srn_clones_cv[clone]); +		mutex_exit(&srn_clone_lock); +		return (0); + +	case SRN_IOC_RESUME: +		/* ack resume */ +		PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone)) +		mutex_enter(&srn_clone_lock); +		if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) { +			mutex_exit(&srn_clone_lock); +			PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n")) +			return (EINVAL); +		} +		srn.srn_delivered[clone] = 0; +		srn.srn_pending[clone].ae_type = 0; +		/* notify the kernel resume thread  to continue */ +		PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone)) +		cv_signal(&srn_clones_cv[clone]); +		mutex_exit(&srn_clone_lock); +		return (0); + +	default: +		PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n")) +		return (EINVAL); +	} +} +/* + * A very simple handshake with the srn driver, + * only one outstanding event at a time. + * The OS delivers the event and depending on type, + * either blocks waiting for the ack, or drives on + */ +void +srn_notify(int type, int event) +{ +	int clone, count; +	PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n", +	    type, event)); +	ASSERT(mutex_owned(&srn_clone_lock)); +	switch (type) { +	case SRN_TYPE_APM: +		if (srn_apm_count == 0) { +			PMD(PMD_SX, ("no apm types\n")) +			return; +		} +		count = srn_apm_count; +		break; +	case SRN_TYPE_AUTOSX: +		if (srn_autosx_count == 0) { +			PMD(PMD_SX, ("no autosx types\n")) +			return; +		} +		count = srn_autosx_count; +		break; +	default: +		ASSERT(0); +		break; +	} +	ASSERT(count > 0); +	PMD(PMD_SX, ("count %d\n", count)) +	for (clone = 0; clone < SRN_MAX_CLONE; clone++) { +		if (srn.srn_type[clone] == type) { +			if (type == SRN_TYPE_APM) { +				ASSERT(srn.srn_pending[clone].ae_type == 0); +				ASSERT(srn_poll_cnt[clone] == 0); +				ASSERT(srn.srn_delivered[clone] == 0); +			} +			srn.srn_pending[clone].ae_type = event; +			srn_poll_cnt[clone] = 1; +			PMD(PMD_SX, ("pollwake %d\n", clone)) +			pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN)); +			count--; +			if (count == 0) +				break; +		} +	} +	if (type == SRN_TYPE_AUTOSX) {		/* we don't wait */ +		PMD(PMD_SX, ("Not waiting for AUTOSX ack\n")) +		return; +	} +	ASSERT(type == SRN_TYPE_APM); +	/* otherwise wait for acks */ +restart: +	/* +	 * We wait untill all of the pending events are cleared. +	 * We have to start over every time we do a cv_wait because +	 * we give up the mutex and can be re-entered +	 */ +	for (clone = 1; clone < SRN_MAX_CLONE; clone++) { +		if (srn.srn_clones[clone] == 0 || +		    srn.srn_type[clone] != SRN_TYPE_APM) +			continue; +		if (srn.srn_pending[clone].ae_type) { +			PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, " +			    "event %x\n", clone, event)) +			cv_wait(&srn_clones_cv[clone], &srn_clone_lock); +			goto restart; +		} +	} +	PMD(PMD_SX, ("srn_notify done with %x\n", event)) +} diff --git a/usr/src/uts/common/io/srn.conf b/usr/src/uts/common/io/srn.conf new file mode 100755 index 0000000000..7db6545647 --- /dev/null +++ b/usr/src/uts/common/io/srn.conf @@ -0,0 +1,27 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2007 Sun Microsystems, Inc.  All rights reserved. +# Use is subject to license terms. +# +#ident	"%Z%%M%	%I%	%E% SMI" + +name="srn" parent="pseudo" instance=0; diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci.c index 3b986e1723..93b7815a7d 100644 --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci.c +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci.c @@ -19,7 +19,7 @@   * CDDL HEADER END   */  /* - * Copyright 2006 Sun Microsystems, Inc.  All rights reserved. + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.   * Use is subject to license terms.   */ @@ -65,6 +65,11 @@ uint_t ehci_errmask	= (uint_t)PRINT_MASK_ALL;  uint_t ehci_errlevel	= USB_LOG_L2;  uint_t ehci_instance_debug = (uint_t)-1; +/* + * Tunable to ensure host controller goes off even if a keyboard is attached. + */ +int force_ehci_off = 1; +  /* Enable all workarounds for VIA VT62x2 */  uint_t ehci_vt62x2_workaround = EHCI_VIA_WORKAROUNDS; diff --git a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c index bc760adfc8..44e6688a4b 100644 --- a/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c +++ b/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c @@ -54,6 +54,7 @@ extern void *ehci_statep;  extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);  extern uint_t ehci_vt62x2_workaround; +extern int force_ehci_off;  /* Adjustable variables for the size of the pools */  int ehci_qh_pool_size = EHCI_QH_POOL_SIZE; @@ -2006,7 +2007,7 @@ ehci_cpr_suspend(ehci_state_t	*ehcip)  	 * Stop the ehci host controller  	 * if usb keyboard is not connected.  	 */ -	if (ehcip->ehci_polled_kbd_count == 0) { +	if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) {  		Set_OpReg(ehci_command,  		    Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);  	} diff --git a/usr/src/uts/common/io/usb/hcd/openhci/ohci.c b/usr/src/uts/common/io/usb/hcd/openhci/ohci.c index 2cb62f57ee..bbfef3dff2 100644 --- a/usr/src/uts/common/io/usb/hcd/openhci/ohci.c +++ b/usr/src/uts/common/io/usb/hcd/openhci/ohci.c @@ -47,6 +47,8 @@  /* Pointer to the state structure */  static void *ohci_statep; +int force_ohci_off = 1; +  /* Number of instances */  #define	OHCI_INSTS	1 @@ -2353,7 +2355,7 @@ ohci_cpr_suspend(ohci_state_t	*ohcip)  	 * Suspend the ohci host controller  	 * if usb keyboard is not connected.  	 */ -	if (ohcip->ohci_polled_kbd_count == 0) { +	if (ohcip->ohci_polled_kbd_count == 0 || force_ohci_off != 0) {  		Set_OpReg(hcr_control, HCR_CONTROL_SUSPD);  	} | 
