Esempio n. 1
0
int main(void)
{
	/* This is a fairly solid assumption that the math we're doing
	 * is based on tb_hz of exactly 512mhz.
	 * If we do start doing the math on different tb_hz, you probably
	 * want to go and audit every bit of code that touches tb to
	 * count/delay things.
	 */
	assert(tb_hz == 512000000);
	assert(secs_to_tb(1) == tb_hz);
	assert(secs_to_tb(2) == 1024000000);
	assert(secs_to_tb(10) == 5120000000);
	assert(tb_to_secs(512000000) == 1);
	assert(tb_to_secs(5120000000) == 10);
	assert(tb_to_secs(1024000000) == 2);

	assert(msecs_to_tb(1) == 512000);
	assert(msecs_to_tb(100) == 51200000);
	assert(msecs_to_tb(5) == 2560000);
	assert(tb_to_msecs(512000) == 1);

	assert(usecs_to_tb(5) == 2560);
	assert(tb_to_usecs(2560) == 5);
	assert(usecs_to_tb(5)*1000 == msecs_to_tb(5));
	assert(tb_to_usecs(512000) == 1000);

	assert(tb_compare(msecs_to_tb(5), usecs_to_tb(5)) == TB_AAFTERB);
	assert(tb_compare(msecs_to_tb(5), usecs_to_tb(50000)) == TB_ABEFOREB);
	assert(tb_compare(msecs_to_tb(5), usecs_to_tb(5)*1000) == TB_AEQUALB);

	return 0;
}
Esempio n. 2
0
/* This is called with the timer lock held, so there is no
 * issue with re-entrancy or concurrence
 */
void p8_sbe_update_timer_expiry(uint64_t new_target)
{
	uint64_t count, gen, gen2, req, now;
	int64_t rc;

	if (!sbe_has_timer || new_target == sbe_timer_target)
		return;

	sbe_timer_target = new_target;

	_xscom_lock();
	now = mftb();
	/* Calculate how many increments from now, rounded up */
	if (now < new_target)
		count = (new_target - now + sbe_timer_inc - 1) / sbe_timer_inc;
	else
		count = 1;

	/* Max counter is 24-bit */
	if (count > 0xffffff)
		count = 0xffffff;
	/* Fabricate update request */
	req = (1ull << 63) | (count << 32);

	prlog(PR_TRACE, "SLW: TMR expiry: 0x%llx, req: %016llx\n", count, req);

	do {
		/* Grab generation and spin if odd */
		for (;;) {
			rc = _xscom_read(sbe_timer_chip, 0xE0006, &gen, false);
			if (rc) {
				prerror("SLW: Error %lld reading tmr gen "
					" count\n", rc);
				_xscom_unlock();
				return;
			}
			if (!(gen & 1))
				break;
			if (tb_compare(now + msecs_to_tb(1), mftb()) == TB_ABEFOREB) {
				/**
				 * @fwts-label SLWTimerStuck
				 * @fwts-advice The SLeep/Winkle Engine (SLW)
				 * failed to increment the generation number
				 * within our timeout period (it *should* have
				 * done so within ~10us, not >1ms. OPAL uses
				 * the SLW timer to schedule some operations,
				 * but can fall back to the (much less frequent
				 * OPAL poller, which although does not affect
				 * functionality, runs *much* less frequently.
				 * This could have the effect of slow I2C
				 * operations (for example). It may also mean
				 * that you *had* an increase in jitter, due
				 * to slow interactions with SLW.
				 * This error may also occur if the machine
				 * is connected to via soft FSI.
				 */
				prerror("SLW: timer stuck, falling back to OPAL pollers. You will likely have slower I2C and may have experienced increased jitter.\n");
				prlog(PR_DEBUG, "SLW: Stuck with odd generation !\n");
				_xscom_unlock();
				sbe_has_timer = false;
				p8_sbe_dump_timer_ffdc();
				return;
			}
		}

		rc = _xscom_write(sbe_timer_chip, 0x5003A, req, false);
		if (rc) {
			prerror("SLW: Error %lld writing tmr request\n", rc);
			_xscom_unlock();
			return;
		}

		/* Re-check gen count */
		rc = _xscom_read(sbe_timer_chip, 0xE0006, &gen2, false);
		if (rc) {
			prerror("SLW: Error %lld re-reading tmr gen "
				" count\n", rc);
			_xscom_unlock();
			return;
		}
	} while(gen != gen2);
	_xscom_unlock();

	/* Check if the timer is working. If at least 1ms has elapsed
	 * since the last call to this function, check that the gen
	 * count has changed
	 */
	if (tb_compare(sbe_last_gen_stamp + msecs_to_tb(1), now)
	    == TB_ABEFOREB) {
		if (sbe_last_gen == gen) {
			prlog(PR_ERR,
			      "SLW: Timer appears to not be running !\n");
			sbe_has_timer = false;
			p8_sbe_dump_timer_ffdc();
		}
		sbe_last_gen = gen;
		sbe_last_gen_stamp = mftb();
	}

	prlog(PR_TRACE, "SLW: gen: %llx\n", gen);
}