 e3d0814368
			
		
	
	
		e3d0814368
		
	
	
	
	
		
			
			Use device_class_set_legacy_reset() instead of opencoding an
assignment to DeviceClass::reset. This change was produced
with:
 spatch --macro-file scripts/cocci-macro-file.h \
    --sp-file scripts/coccinelle/device-reset.cocci \
    --keep-comments --smpl-spacing --in-place --dir hw
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20240830145812.1967042-8-peter.maydell@linaro.org
		
	
			
		
			
				
	
	
		
			153 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Aspeed PECI Controller
 | |
|  *
 | |
|  * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
 | |
|  *
 | |
|  * This code is licensed under the GPL version 2 or later. See the COPYING
 | |
|  * file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu/log.h"
 | |
| #include "hw/irq.h"
 | |
| #include "hw/misc/aspeed_peci.h"
 | |
| #include "hw/registerfields.h"
 | |
| #include "trace.h"
 | |
| 
 | |
| #define ASPEED_PECI_CC_RSP_SUCCESS (0x40U)
 | |
| 
 | |
| /* Command Register */
 | |
| REG32(PECI_CMD, 0x08)
 | |
|     FIELD(PECI_CMD, FIRE, 0, 1)
 | |
| 
 | |
| /* Interrupt Control Register */
 | |
| REG32(PECI_INT_CTRL, 0x18)
 | |
| 
 | |
| /* Interrupt Status Register */
 | |
| REG32(PECI_INT_STS, 0x1C)
 | |
|     FIELD(PECI_INT_STS, CMD_DONE, 0, 1)
 | |
| 
 | |
| /* Rx/Tx Data Buffer Registers */
 | |
| REG32(PECI_WR_DATA0, 0x20)
 | |
| REG32(PECI_RD_DATA0, 0x30)
 | |
| 
 | |
| static void aspeed_peci_raise_interrupt(AspeedPECIState *s, uint32_t status)
 | |
| {
 | |
|     trace_aspeed_peci_raise_interrupt(s->regs[R_PECI_INT_CTRL], status);
 | |
| 
 | |
|     s->regs[R_PECI_INT_STS] = s->regs[R_PECI_INT_CTRL] & status;
 | |
|     if (!s->regs[R_PECI_INT_STS]) {
 | |
|         return;
 | |
|     }
 | |
|     qemu_irq_raise(s->irq);
 | |
| }
 | |
| 
 | |
| static uint64_t aspeed_peci_read(void *opaque, hwaddr offset, unsigned size)
 | |
| {
 | |
|     AspeedPECIState *s = ASPEED_PECI(opaque);
 | |
|     uint64_t data;
 | |
| 
 | |
|     if (offset >= ASPEED_PECI_NR_REGS << 2) {
 | |
|         qemu_log_mask(LOG_GUEST_ERROR,
 | |
|                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
 | |
|                       __func__, offset);
 | |
|         return 0;
 | |
|     }
 | |
|     data = s->regs[offset >> 2];
 | |
| 
 | |
|     trace_aspeed_peci_read(offset, data);
 | |
|     return data;
 | |
| }
 | |
| 
 | |
| static void aspeed_peci_write(void *opaque, hwaddr offset, uint64_t data,
 | |
|                               unsigned size)
 | |
| {
 | |
|     AspeedPECIState *s = ASPEED_PECI(opaque);
 | |
| 
 | |
|     trace_aspeed_peci_write(offset, data);
 | |
| 
 | |
|     if (offset >= ASPEED_PECI_NR_REGS << 2) {
 | |
|         qemu_log_mask(LOG_GUEST_ERROR,
 | |
|                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
 | |
|                       __func__, offset);
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     switch (offset) {
 | |
|     case A_PECI_INT_STS:
 | |
|         s->regs[R_PECI_INT_STS] &= ~data;
 | |
|         if (!s->regs[R_PECI_INT_STS]) {
 | |
|             qemu_irq_lower(s->irq);
 | |
|         }
 | |
|         break;
 | |
|     case A_PECI_CMD:
 | |
|         /*
 | |
|          * Only the FIRE bit is writable. Once the command is complete, it
 | |
|          * should be cleared. Since we complete the command immediately, the
 | |
|          * value is not stored in the register array.
 | |
|          */
 | |
|         if (!FIELD_EX32(data, PECI_CMD, FIRE)) {
 | |
|             break;
 | |
|         }
 | |
|         if (s->regs[R_PECI_INT_STS]) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: Interrupt status must be "
 | |
|                           "cleared before firing another command: 0x%08x\n",
 | |
|                           __func__, s->regs[R_PECI_INT_STS]);
 | |
|             break;
 | |
|         }
 | |
|         s->regs[R_PECI_RD_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
 | |
|         s->regs[R_PECI_WR_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
 | |
|         aspeed_peci_raise_interrupt(s,
 | |
|                                     FIELD_DP32(0, PECI_INT_STS, CMD_DONE, 1));
 | |
|         break;
 | |
|     default:
 | |
|         s->regs[offset / sizeof(s->regs[0])] = data;
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static const MemoryRegionOps aspeed_peci_ops = {
 | |
|     .read = aspeed_peci_read,
 | |
|     .write = aspeed_peci_write,
 | |
|     .endianness = DEVICE_LITTLE_ENDIAN,
 | |
| };
 | |
| 
 | |
| static void aspeed_peci_realize(DeviceState *dev, Error **errp)
 | |
| {
 | |
|     AspeedPECIState *s = ASPEED_PECI(dev);
 | |
|     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 | |
| 
 | |
|     memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_peci_ops, s,
 | |
|                           TYPE_ASPEED_PECI, 0x1000);
 | |
|     sysbus_init_mmio(sbd, &s->mmio);
 | |
|     sysbus_init_irq(sbd, &s->irq);
 | |
| }
 | |
| 
 | |
| static void aspeed_peci_reset(DeviceState *dev)
 | |
| {
 | |
|     AspeedPECIState *s = ASPEED_PECI(dev);
 | |
| 
 | |
|     memset(s->regs, 0, sizeof(s->regs));
 | |
| }
 | |
| 
 | |
| static void aspeed_peci_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
| 
 | |
|     dc->realize = aspeed_peci_realize;
 | |
|     device_class_set_legacy_reset(dc, aspeed_peci_reset);
 | |
|     dc->desc = "Aspeed PECI Controller";
 | |
| }
 | |
| 
 | |
| static const TypeInfo aspeed_peci_types[] = {
 | |
|     {
 | |
|         .name = TYPE_ASPEED_PECI,
 | |
|         .parent = TYPE_SYS_BUS_DEVICE,
 | |
|         .instance_size = sizeof(AspeedPECIState),
 | |
|         .class_init = aspeed_peci_class_init,
 | |
|         .abstract = false,
 | |
|     },
 | |
| };
 | |
| 
 | |
| DEFINE_TYPES(aspeed_peci_types);
 |