From nobody Tue May 7 23:54:29 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1493780310141185.38469448512; Tue, 2 May 2017 19:58:30 -0700 (PDT) Received: from localhost ([::1]:34490 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d5kUm-0007iA-AL for importer@patchew.org; Tue, 02 May 2017 22:58:28 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50012) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d5kTv-0007NK-22 for qemu-devel@nongnu.org; Tue, 02 May 2017 22:57:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d5kTs-00042r-CZ for qemu-devel@nongnu.org; Tue, 02 May 2017 22:57:35 -0400 Received: from linux03.ddci.com ([184.183.10.182]:60459 helo=linux03a.ddci.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1d5kTs-00042T-1P; Tue, 02 May 2017 22:57:32 -0400 Received: from linux03a.ddci.com (localhost.localdomain [127.0.0.1]) by linux03a.ddci.com (8.13.8/8.13.8) with ESMTP id v432vPZ0008048; Tue, 2 May 2017 19:57:25 -0700 Received: (from alarson@localhost) by linux03a.ddci.com (8.13.8/8.13.8/Submit) id v432vMO2008047; Tue, 2 May 2017 19:57:22 -0700 Date: Tue, 2 May 2017 19:57:22 -0700 From: Aaron Larson Message-Id: <201705030257.v432vMO2008047@linux03a.ddci.com> To: agraf@suse.de, alarson@ddci.com, david@gibson.dropbear.id.au, qemu-devel@nongnu.org, qemu-ppc@nongnu.org X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x [fuzzy] X-Received-From: 184.183.10.182 Subject: [Qemu-devel] [PATCH v2] target-ppc: Enable open-pic timers to count and generate interrupts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Previous QEMU open-pic implemented the 4 open-pic timers including all timer registers, but the timers did not "count" or generate any interrupts. The patch makes the timers both count and generate interrupts. The timer clock frequency is fixed at 100MHZ. Signed-off-by: Aaron Larson --- hw/intc/openpic.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 117 insertions(+), 18 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 4349e45..e0556f1 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -45,6 +45,7 @@ #include "qemu/bitops.h" #include "qapi/qmp/qerror.h" #include "qemu/log.h" +#include "qemu/timer.h" =20 //#define DEBUG_OPENPIC =20 @@ -54,8 +55,10 @@ static const int debug_openpic =3D 1; static const int debug_openpic =3D 0; #endif =20 +static int get_current_cpu(void); #define DPRINTF(fmt, ...) do { \ if (debug_openpic) { \ + printf("Core%d: ", get_current_cpu()); \ printf(fmt , ## __VA_ARGS__); \ } \ } while (0) @@ -246,9 +249,25 @@ typedef struct IRQSource { #define IDR_EP 0x80000000 /* external pin */ #define IDR_CI 0x40000000 /* critical interrupt */ =20 +/* Conversion between openpic clock ticks and nanosecs. Ideally this clock + frequency would follow the openpic spec, for now hard code to 100mz. + A 100mhz clock, divided by 8, or 25mhz + 25,000,000 ticks/sec, 25,000/ms, 25/us, 1 tick/40ns +*/ +#define CONV_FACTOR 40LL +static inline uint64_t ns_to_ticks(uint64_t ns) { return ns / CONV_FAC= TOR; } +static inline uint64_t ticks_to_ns(uint64_t tick) { return tick * CONV_FAC= TOR; } + typedef struct OpenPICTimer { uint32_t tccr; /* Global timer current count register */ uint32_t tbcr; /* Global timer base count register */ + int n_IRQ; + bool qemu_timer_active; /* Is the qemu_timer is runni= ng? */ + struct QEMUTimer *qemu_timer; /* May be NULL if not created. */ + struct OpenPICState *opp; /* Device timer is part of. */ + /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last + current_count written or read, only defined if qemu_timer_active. */ + uint64_t originTime; } OpenPICTimer; =20 typedef struct OpenPICMSI { @@ -795,37 +814,102 @@ static uint64_t openpic_gbl_read(void *opaque, hwadd= r addr, unsigned len) return retval; } =20 +static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enab= led); + +static void qemu_timer_cb(void *opaque) +{ + OpenPICTimer *tmr =3D opaque; + OpenPICState *opp =3D tmr->opp; + uint32_t n_IRQ =3D tmr->n_IRQ; + uint32_t val =3D tmr->tbcr & ~TBCR_CI; + uint32_t tog =3D ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggl= e. */ + + DPRINTF("%s n_IRQ=3D%d\n", __func__, n_IRQ); + /* Reload current count from base count and setup timer. */ + tmr->tccr =3D val | tog; + openpic_tmr_set_tmr(tmr, val, /*enabled=3D*/true); + /* Raise the interrupt. */ + opp->src[n_IRQ].destmask =3D read_IRQreg_idr(opp, n_IRQ); + openpic_set_irq(opp, n_IRQ, 1); + openpic_set_irq(opp, n_IRQ, 0); +} + +/* If enabled is true, arranges for an interrupt to be raised val clocks i= nto + the future, if enabled is false cancels the timer. */ +static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enab= led) +{ + /* If timer doesn't exist, create it. */ + if (tmr->qemu_timer =3D=3D NULL) { + tmr->qemu_timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, &qemu_timer_c= b, tmr); + DPRINTF("Created timer for n_IRQ %d\n", tmr->n_IRQ); + } + uint64_t ns =3D ticks_to_ns(val & ~TCCR_TOG); + /* A count of zero causes a timer to be set to expire immediately. Th= is + effectively stops the simulation so we don't honor that configurati= on. + On real hardware, this would generate an interrupt on every clock c= ycle + if the interrupt was unmasked. */ + if ((ns =3D=3D 0) || !enabled) { + tmr->qemu_timer_active =3D false; + tmr->tccr =3D tmr->tccr & TCCR_TOG; + timer_del(tmr->qemu_timer); /* set timer to never expire. */ + } else { + tmr->qemu_timer_active =3D true; + uint64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + tmr->originTime =3D now; + timer_mod(tmr->qemu_timer, now + ns); /* set timer expiration.= */ + } +} + +/* Returns the currrent tccr value, i.e., timer value (in clocks) with + appropriate TOG. */ +static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr) +{ + uint64_t retval; + if (!tmr->qemu_timer_active) { + retval =3D tmr->tccr; + } else { + uint64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint64_t used =3D now - tmr->originTime; /* nsecs */ + uint32_t used_ticks =3D (uint32_t)ns_to_ticks(used); + uint32_t count =3D (tmr->tccr & ~TCCR_TOG) - used_ticks; + retval =3D (uint32_t)((tmr->tccr & TCCR_TOG) | (count & ~TCCR_TOG)= ); + } + return retval; +} + static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, - unsigned len) + unsigned len) { OpenPICState *opp =3D opaque; int idx; =20 - addr +=3D 0x10f0; - DPRINTF("%s: addr %#" HWADDR_PRIx " <=3D %08" PRIx64 "\n", - __func__, addr, val); + __func__, (addr + 0x10f0), val); if (addr & 0xF) { return; } =20 - if (addr =3D=3D 0x10f0) { + if (addr =3D=3D 0) { /* TFRR */ opp->tfrr =3D val; return; } - + addr -=3D 0x10; /* correct for TFRR */ idx =3D (addr >> 6) & 0x3; - addr =3D addr & 0x30; =20 switch (addr & 0x30) { case 0x00: /* TCCR */ break; case 0x10: /* TBCR */ - if ((opp->timers[idx].tccr & TCCR_TOG) !=3D 0 && - (val & TBCR_CI) =3D=3D 0 && - (opp->timers[idx].tbcr & TBCR_CI) !=3D 0) { - opp->timers[idx].tccr &=3D ~TCCR_TOG; + /* Did the enable status change? */ + if ((opp->timers[idx].tbcr & TBCR_CI) !=3D (val & TBCR_CI)) { + /* Did "Count Inhibit" transition from 1 to 0? */ + if ((val & TBCR_CI) =3D=3D 0) { + opp->timers[idx].tccr =3D val & ~TCCR_TOG; + } + openpic_tmr_set_tmr(&opp->timers[idx], + (val & ~TBCR_CI), + /*enabled=3D*/((val & TBCR_CI) =3D=3D 0)); } opp->timers[idx].tbcr =3D val; break; @@ -844,27 +928,28 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr= addr, unsigned len) uint32_t retval =3D -1; int idx; =20 - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0); if (addr & 0xF) { goto out; } - idx =3D (addr >> 6) & 0x3; - if (addr =3D=3D 0x0) { + if (addr =3D=3D 0) { /* TFRR */ retval =3D opp->tfrr; goto out; } + addr -=3D 0x10; /* correct for TFRR */ + idx =3D (addr >> 6) & 0x3; switch (addr & 0x30) { case 0x00: /* TCCR */ - retval =3D opp->timers[idx].tccr; + retval =3D openpic_tmr_get_timer(&opp->timers[idx]); break; case 0x10: /* TBCR */ retval =3D opp->timers[idx].tbcr; break; - case 0x20: /* TIPV */ + case 0x20: /* TVPR */ retval =3D read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); break; - case 0x30: /* TIDE (TIDR) */ + case 0x30: /* TDR */ retval =3D read_IRQreg_idr(opp, opp->irq_tim0 + idx); break; } @@ -1138,7 +1223,10 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQD= est *dst, int cpu) IRQ_resetbit(&dst->raised, irq); } =20 - if ((irq >=3D opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_I= PI))) { + /* Timers and IPIs support multicast. */ + if (((irq >=3D opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_I= PI))) || + ((irq >=3D opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_T= MR)))) { + DPRINTF("irq is IPI or TMR\n"); src->destmask &=3D ~(1 << cpu); if (src->destmask && !src->level) { /* trigger on CPUs that didn't know about it yet */ @@ -1343,6 +1431,10 @@ static void openpic_reset(DeviceState *d) for (i =3D 0; i < OPENPIC_MAX_TMR; i++) { opp->timers[i].tccr =3D 0; opp->timers[i].tbcr =3D TBCR_CI; + if (opp->timers[i].qemu_timer_active) { + timer_del(opp->timers[i].qemu_timer); /* Inhibit timer */ + opp->timers[i].qemu_timer_active =3D false; + } } /* Go out of RESET state */ opp->gcr =3D 0; @@ -1393,6 +1485,13 @@ static void fsl_common_init(OpenPICState *opp) opp->src[i].type =3D IRQ_TYPE_FSLSPECIAL; opp->src[i].level =3D false; } + + for (i =3D 0; i < OPENPIC_MAX_TMR; i++) { + opp->timers[i].n_IRQ =3D opp->irq_tim0 + i; + opp->timers[i].qemu_timer_active =3D false; + opp->timers[i].qemu_timer =3D NULL; + opp->timers[i].opp =3D opp; + } } =20 static void map_list(OpenPICState *opp, const MemReg *list, int *count) --=20 2.7.4