[Skiboot] [PATCH RESEND v6 2/2] SBE: Add timer support

Benjamin Herrenschmidt benh at kernel.crashing.org
Tue Apr 17 13:40:18 AEST 2018


On Mon, 2018-04-16 at 15:26 +0530, Vasant Hegde wrote:
> 
> > >   	/* SBE came back from reset */
> > >   	if (data & SBE_HOST_RESET) {
> > >   		prlog(PR_NOTICE, "Back from reset [chip id = %x]\n", chip_id);
> > > @@ -547,6 +586,9 @@ clr_interrupt:
> > >   
> > >   	p9_sbe_process_queue(sbe);
> > >   	unlock(&sbe->lock);
> > > +	/* Drop lock and call timers */
> > > +	if (timer_interrupt)
> > > +		check_timers(true);
> > 
> > If for some reason the timer fired early, are you confident it will be
> > re-armed ?
> 
> Our understanding is SBE will never get back to us early. They will always come 
> after timeout.
> So we are good here.

No, you need to ensure you are robust. It could be something as simple
as the clock drifting between the SBE and the CPU for example.

> > 
> > >   }
> > >   
> > >   static void p9_sbe_timeout_poll(void *user_data __unused)
> > > @@ -598,6 +640,120 @@ static void p9_sbe_timeout_poll(void *user_data __unused)
> > >   		p9_sbe_process_queue(sbe);
> > >   		unlock(&sbe->lock);
> > >   	}
> > > +
> > > +	/*
> > > +	 * Check if the timer is working. If at least 1ms elapsed since
> > > +	 * last scheduled timer expiry.
> > > +	 */
> > > +	if (sbe_has_timer && sbe_timer_in_progress) {
> > > +		chip = get_chip(sbe_default_chip_id);
> > > +		sbe = chip->sbe;
> > > +		if (tb_compare(mftb(), sbe_last_gen_stamp + msecs_to_tb(1))
> > > +		    != TB_AAFTERB)
> > > +			return;
> > 
> > So I would have put that inside the above lock section, basically, if
> > the chip is the default chip, add the timeout logic (and move it to a
> > separate function).
> 
> Yeah. I will have separate p9_sbe_timer_poll() to timer timeout checking. Also I 
> will move above block  inside lock.
> 
> > 
> > > +		/*
> > > +		 * In some cases there will be a delay in calling OPAL interrupt
> > > +		 * handler routine (opal_handle_interrupt). In such cases its
> > > +		 * possible that SBE has responded, but OPAL didn't act on that.
> > > +		 * Hence check for SBE response before disabling timer.
> > > +		 */
> > > +		p9_sbe_interrupt(sbe_default_chip_id);
> > 
> > 
> > Otherwise you call the above twice in the same function and the
> > function becomes a mess.
> > 
> > Also you keep taking & releasing the lock, it's inefficient. Follow my
> > advice in the other patch, have the lock taken once in a per-chip thing
> > and everything else underneath is done with that one lock instance.
> 
> Agree. Moved to separate function.
> 
> 
> > 
> > > +
> > > +		lock(&sbe->lock);
> > > +		if (!sbe_timer_in_progress) {
> > > +			unlock(&sbe->lock);
> > > +			return;
> > > +		}
> > > +
> > > +		if (tb_compare(mftb(), sbe_last_gen_stamp + msecs_to_tb(1))
> > > +		    != TB_AAFTERB) {
> > > +			unlock(&sbe->lock);
> > > +			return;
> > > +		}
> > > +
> > > +		prlog(PR_ERR, "Timer stuck, falling back to OPAL pollers.\n");
> > > +		prlog(PR_ERR, "You will likely have slower I2C and may have "
> > > +		      "experienced increased jitter.\n");
> > > +		p9_sbe_reg_dump(sbe_default_chip_id);
> > > +		sbe_has_timer = false;
> > > +		sbe_timer_in_progress = false;
> > > +		unlock(&sbe->lock);
> > > +	}
> > > +}
> > > +
> > > +/*
> > > + * This is called with the timer lock held, so there is no
> > > + * issue with re-entrancy or concurrence
> > > + */
> > > +void p9_sbe_update_timer_expiry(uint64_t new_target)
> > > +{
> > > +	int rc;
> > > +	u32 tick_us = SBE_TIMER_DEFAULT_US;
> > > +	u64 tb_cnt, now = mftb();
> > > +
> > > +	if (!sbe_has_timer || new_target == sbe_timer_target)
> > > +		return;
> > > +
> > > +	sbe_timer_target = new_target;
> > > +
> > > +	/* Modify timer */
> > > +	if (sbe_timer_in_progress) {
> > > +		if (sbe_timer_target < now)
> > > +			return;
> > > +
> > > +		/* remaining time <= sbe_timer_def_tb */
> > > +		if ((sbe_last_gen_stamp - now) <= sbe_timer_def_tb)
> > > +			return;
> > > +
> > > +		if (sbe_timer_target > sbe_last_gen_stamp)
> > > +			return;
> > > +
> > > +		sbe_timer_in_progress = false;
> > 
> > So aren't you potentially re-using or modifying a message that is in
> > the middle of being sent ?
> > 
> > IE a previous call to p9_sbe_update_timer_expiry has queued the
> > message, it's now in the process of being sent, while this gets called,
> > cleares sbe_timer_in_progress, ad move on with hacking the "active"
> > message ... that isn't right.
> > 
> > You need to flag that a new target is needed and prep a new message
> > from the completion of the previous one.
> 
> Done.
> 
> I'm moving from sync msg to async message. Also I've "has_new_target" note down 
> new timer value while we are processing current timer.
> 
> Thanks
> -Vasant


More information about the Skiboot mailing list