~ressu/+junk/xen-ubuntu

« back to all changes in this revision

Viewing changes to xen/arch/x86/hvm/pmtimer.c

  • Committer: sami at haahtinen
  • Date: 2011-05-23 19:11:45 UTC
  • mfrom: (3.1.3 xen)
  • Revision ID: sami@haahtinen.name-20110523191145-55rhsn3endndbbge
* Upload new version to ppa, base off the 4.1.0 package in debian
* Re-enable hvmloader:
  - Use packaged ipxe.
* Workaround incompatibility with xenstored of Xen 4.0.
* New upstream release.
* New upstream release candidate.
* Build documentation using pdflatex.
* Use python 2.6. (closes: #596545)
* Fix lintian override.
* Install new tools: xl, xenpaging.
* Enable blktap2.
  - Use own md5 implementation.
  - Fix includes.
  - Fix linking of blktap2 binaries.
  - Remove optimization setting.
* Temporarily disable hvmloader, wants to download ipxe.
* Remove xenstored pid check from xl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include <asm/hvm/io.h>
23
23
#include <asm/hvm/support.h>
24
24
#include <asm/acpi.h> /* for hvm_acpi_power_button prototype */
 
25
#include <public/hvm/params.h>
25
26
 
26
27
/* Slightly more readable port I/O addresses for the registers we intercept */
27
 
#define PM1a_STS_ADDR (ACPI_PM1A_EVT_BLK_ADDRESS)
28
 
#define PM1a_EN_ADDR  (ACPI_PM1A_EVT_BLK_ADDRESS + 2)
29
 
#define TMR_VAL_ADDR  (ACPI_PM_TMR_BLK_ADDRESS)
 
28
#define PM1a_STS_ADDR_V0 (ACPI_PM1A_EVT_BLK_ADDRESS_V0)
 
29
#define PM1a_EN_ADDR_V0  (ACPI_PM1A_EVT_BLK_ADDRESS_V0 + 2)
 
30
#define TMR_VAL_ADDR_V0  (ACPI_PM_TMR_BLK_ADDRESS_V0)
 
31
#define PM1a_STS_ADDR_V1 (ACPI_PM1A_EVT_BLK_ADDRESS_V1)
 
32
#define PM1a_EN_ADDR_V1  (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 2)
 
33
#define TMR_VAL_ADDR_V1  (ACPI_PM_TMR_BLK_ADDRESS_V1)
30
34
 
31
35
/* The interesting bits of the PM1a_STS register */
32
36
#define TMR_STS    (1 << 0)
83
87
 * since the last time we did that. */
84
88
static void pmt_update_time(PMTState *s)
85
89
{
86
 
    uint64_t curr_gtime;
87
 
    uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB;
 
90
    uint64_t curr_gtime, tmp;
 
91
    uint32_t tmr_val = s->pm.tmr_val, msb = tmr_val & TMR_VAL_MSB;
88
92
    
89
93
    ASSERT(spin_is_locked(&s->lock));
90
94
 
91
95
    /* Update the timer */
92
96
    curr_gtime = hvm_get_guest_time(s->vcpu);
93
 
    s->pm.tmr_val += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
94
 
    s->pm.tmr_val &= TMR_VAL_MASK;
 
97
    tmp = ((curr_gtime - s->last_gtime) * s->scale) + s->not_accounted;
 
98
    s->not_accounted = (uint32_t)tmp;
 
99
    tmr_val += tmp >> 32;
 
100
    tmr_val &= TMR_VAL_MASK;
95
101
    s->last_gtime = curr_gtime;
96
 
    
 
102
 
 
103
    /* Update timer value atomically wrt lock-free reads in handle_pmt_io(). */
 
104
    *(volatile uint32_t *)&s->pm.tmr_val = tmr_val;
 
105
 
97
106
    /* If the counter's MSB has changed, set the status bit */
98
 
    if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb )
 
107
    if ( (tmr_val & TMR_VAL_MSB) != msb )
99
108
    {
100
109
        s->pm.pm1a_sts |= TMR_STS;
101
110
        pmt_update_sci(s);
140
149
    uint32_t addr, data, byte;
141
150
    int i;
142
151
 
 
152
    addr = port -
 
153
        ((v->domain->arch.hvm_domain.params[
 
154
            HVM_PARAM_ACPI_IOPORTS_LOCATION] == 0) ?
 
155
         PM1a_STS_ADDR_V0 : PM1a_STS_ADDR_V1);
 
156
 
143
157
    spin_lock(&s->lock);
144
158
 
145
159
    if ( dir == IOREQ_WRITE )
146
160
    {
147
161
        /* Handle this I/O one byte at a time */
148
 
        for ( i = bytes, addr = port, data = *val;
 
162
        for ( i = bytes, data = *val;
149
163
              i > 0;
150
164
              i--, addr++, data >>= 8 )
151
165
        {
153
167
            switch ( addr )
154
168
            {
155
169
                /* PM1a_STS register bits are write-to-clear */
156
 
            case PM1a_STS_ADDR:
 
170
            case 0 /* PM1a_STS_ADDR */:
157
171
                s->pm.pm1a_sts &= ~byte;
158
172
                break;
159
 
            case PM1a_STS_ADDR + 1:
 
173
            case 1 /* PM1a_STS_ADDR + 1 */:
160
174
                s->pm.pm1a_sts &= ~(byte << 8);
161
175
                break;
162
 
                
163
 
            case PM1a_EN_ADDR:
 
176
            case 2 /* PM1a_EN_ADDR */:
164
177
                s->pm.pm1a_en = (s->pm.pm1a_en & 0xff00) | byte;
165
178
                break;
166
 
            case PM1a_EN_ADDR + 1:
 
179
            case 3 /* PM1a_EN_ADDR + 1 */:
167
180
                s->pm.pm1a_en = (s->pm.pm1a_en & 0xff) | (byte << 8);
168
181
                break;
169
 
                
170
182
            default:
171
183
                gdprintk(XENLOG_WARNING, 
172
184
                         "Bad ACPI PM register write: %x bytes (%x) at %x\n", 
179
191
    else /* p->dir == IOREQ_READ */
180
192
    {
181
193
        data = s->pm.pm1a_sts | (((uint32_t) s->pm.pm1a_en) << 16);
182
 
        data >>= 8 * (port - PM1a_STS_ADDR);
 
194
        data >>= 8 * addr;
183
195
        if ( bytes == 1 ) data &= 0xff;
184
196
        else if ( bytes == 2 ) data &= 0xffff;
185
197
        *val = data;
206
218
    
207
219
    if ( dir == IOREQ_READ )
208
220
    {
209
 
        spin_lock(&s->lock);
210
 
        pmt_update_time(s);
211
 
        *val = s->pm.tmr_val;
212
 
        spin_unlock(&s->lock);
 
221
        if ( spin_trylock(&s->lock) )
 
222
        {
 
223
            /* We hold the lock: update timer value and return it. */
 
224
            pmt_update_time(s);
 
225
            *val = s->pm.tmr_val;
 
226
            spin_unlock(&s->lock);
 
227
        }
 
228
        else
 
229
        {
 
230
            /*
 
231
             * Someone else is updating the timer: rather than do the work
 
232
             * again ourselves, wait for them to finish and then steal their
 
233
             * updated value with a lock-free atomic read.
 
234
             */
 
235
            spin_barrier(&s->lock);
 
236
            *val = *(volatile uint32_t *)&s->pm.tmr_val;
 
237
        }
213
238
        return X86EMUL_OKAY;
214
239
    }
215
240
 
257
282
 
258
283
    /* Calculate future counter values from now. */
259
284
    s->last_gtime = hvm_get_guest_time(s->vcpu);
 
285
    s->not_accounted = 0;
260
286
 
261
287
    /* Set the SCI state from the registers */ 
262
288
    pmt_update_sci(s);
269
295
HVM_REGISTER_SAVE_RESTORE(PMTIMER, pmtimer_save, pmtimer_load, 
270
296
                          1, HVMSR_PER_DOM);
271
297
 
 
298
int pmtimer_change_ioport(struct domain *d, unsigned int version)
 
299
{
 
300
    unsigned int old_version;
 
301
 
 
302
    /* Check that version is changing. */
 
303
    old_version = d->arch.hvm_domain.params[HVM_PARAM_ACPI_IOPORTS_LOCATION];
 
304
    if ( version == old_version )
 
305
        return 0;
 
306
 
 
307
    /* Only allow changes between versions 0 and 1. */
 
308
    if ( (version ^ old_version) != 1 )
 
309
        return -EINVAL;
 
310
 
 
311
    if ( version == 1 )
 
312
    {
 
313
        /* Moving from version 0 to version 1. */
 
314
        relocate_portio_handler(d, TMR_VAL_ADDR_V0, TMR_VAL_ADDR_V1, 4);
 
315
        relocate_portio_handler(d, PM1a_STS_ADDR_V0, PM1a_STS_ADDR_V1, 4);
 
316
    }
 
317
    else
 
318
    {
 
319
        /* Moving from version 1 to version 0. */
 
320
        relocate_portio_handler(d, TMR_VAL_ADDR_V1, TMR_VAL_ADDR_V0, 4);
 
321
        relocate_portio_handler(d, PM1a_STS_ADDR_V1, PM1a_STS_ADDR_V0, 4);
 
322
    }
 
323
 
 
324
    return 0;
 
325
}
 
326
 
272
327
void pmtimer_init(struct vcpu *v)
273
328
{
274
329
    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
276
331
    spin_lock_init(&s->lock);
277
332
 
278
333
    s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / SYSTEM_TIME_HZ;
 
334
    s->not_accounted = 0;
279
335
    s->vcpu = v;
280
336
 
281
337
    /* Intercept port I/O (need two handlers because PM1a_CNT is between
282
338
     * PM1a_EN and TMR_VAL and is handled by qemu) */
283
 
    register_portio_handler(v->domain, TMR_VAL_ADDR, 4, handle_pmt_io);
284
 
    register_portio_handler(v->domain, PM1a_STS_ADDR, 4, handle_evt_io);
 
339
    register_portio_handler(v->domain, TMR_VAL_ADDR_V0, 4, handle_pmt_io);
 
340
    register_portio_handler(v->domain, PM1a_STS_ADDR_V0, 4, handle_evt_io);
285
341
 
286
342
    /* Set up callback to fire SCIs when the MSB of TMR_VAL changes */
287
343
    init_timer(&s->timer, pmt_timer_callback, s, v->processor);