From nobody Wed May 1 04:53:31 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 1492811970688937.6258130448404; Fri, 21 Apr 2017 14:59:30 -0700 (PDT) Received: from localhost ([::1]:33344 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d1gaP-0004jz-2c for importer@patchew.org; Fri, 21 Apr 2017 17:59:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57727) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d1gZW-0004Hv-22 for qemu-devel@nongnu.org; Fri, 21 Apr 2017 17:58:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d1gZR-0008Gz-4t for qemu-devel@nongnu.org; Fri, 21 Apr 2017 17:58:34 -0400 Received: from linux03.ddci.com ([184.183.10.182]:56938 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 1d1gZQ-0008Gk-Pr; Fri, 21 Apr 2017 17:58:29 -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 v3LLwNkc031739; Fri, 21 Apr 2017 14:58:23 -0700 Received: (from alarson@localhost) by linux03a.ddci.com (8.13.8/8.13.8/Submit) id v3LLwNYl031738; Fri, 21 Apr 2017 14:58:23 -0700 Date: Fri, 21 Apr 2017 14:58:23 -0700 From: Aaron Larson Message-Id: <201704212158.v3LLwNYl031738@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] Subject: [PATCH] target-ppc: Add global timer group A to open-pic. 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" Add global timer group A to open-pic. This patch is still somewhat dubious because I'm not sure how to determine what QEMU wants for the timer frequency. Suggestions solicited. Signed-off-by: Aaron Larson --- hw/intc/openpic.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 116 insertions(+), 18 deletions(-) diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 4349e45..769a31a 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,24 @@ typedef struct IRQSource { #define IDR_EP 0x80000000 /* external pin */ #define IDR_CI 0x40000000 /* critical interrupt */ =20 +/* Conversion between ticks and nanosecs: TODO: need better way for this. + Assume 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 0 if not created. */ + struct OpenPICState *opp; /* device timer is part of. */ + /* the time 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 +813,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 0) { + 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 +927,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 +1222,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 +1430,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 0; + } } /* Go out of RESET state */ opp->gcr =3D 0; @@ -1393,6 +1484,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 0; + opp->timers[i].qemu_timer =3D 0; + opp->timers[i].opp =3D opp; + } } =20 static void map_list(OpenPICState *opp, const MemReg *list, int *count) --=20 2.7.4