Commit ca661fae authored by Cédric Le Goater's avatar Cédric Le Goater Committed by David Gibson
Browse files

ppc/pnv: Add HIOMAP commands

This activates HIOMAP support on the QEMU PowerNV machine. The PnvPnor
model is used to access the flash contents. The model simply maps the
contents at a fix offset and enables or disables the mapping.

HIOMAP Protocol description :

  https://github.com/openbmc/hiomapd/blob/master/Documentation/protocol.md



Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Message-Id: <20191028070027.22752-3-clg@kaod.org>
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent ed8da05c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -569,6 +569,7 @@ static void pnv_reset(MachineState *machine)
    obj = object_resolve_path_type("", "ipmi-bmc-sim", NULL);
    if (obj) {
        pnv->bmc = IPMI_BMC(obj);
        pnv_bmc_hiomap(pnv->bmc);
    }

    fdt = pnv_dt_create(machine);
+102 −0
Original line number Diff line number Diff line
@@ -114,3 +114,105 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt)
                               sdr->sensor_type)));
    }
}

/*
 * HIOMAP protocol handler
 */
#define HIOMAP_C_RESET                  1
#define HIOMAP_C_GET_INFO               2
#define HIOMAP_C_GET_FLASH_INFO         3
#define HIOMAP_C_CREATE_READ_WINDOW     4
#define HIOMAP_C_CLOSE_WINDOW           5
#define HIOMAP_C_CREATE_WRITE_WINDOW    6
#define HIOMAP_C_MARK_DIRTY             7
#define HIOMAP_C_FLUSH                  8
#define HIOMAP_C_ACK                    9
#define HIOMAP_C_ERASE                  10
#define HIOMAP_C_DEVICE_NAME            11
#define HIOMAP_C_LOCK                   12

#define BLOCK_SHIFT                     12 /* 4K */

static uint16_t bytes_to_blocks(uint32_t bytes)
{
    return bytes >> BLOCK_SHIFT;
}

static void hiomap_cmd(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len,
                       RspBuffer *rsp)
{
    PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
    PnvPnor *pnor = pnv->pnor;
    uint32_t pnor_size = pnor->size;
    uint32_t pnor_addr = PNOR_SPI_OFFSET;
    bool readonly = false;

    rsp_buffer_push(rsp, cmd[2]);
    rsp_buffer_push(rsp, cmd[3]);

    switch (cmd[2]) {
    case HIOMAP_C_MARK_DIRTY:
    case HIOMAP_C_FLUSH:
    case HIOMAP_C_ERASE:
    case HIOMAP_C_ACK:
        break;

    case HIOMAP_C_GET_INFO:
        rsp_buffer_push(rsp, 2);  /* Version 2 */
        rsp_buffer_push(rsp, BLOCK_SHIFT); /* block size */
        rsp_buffer_push(rsp, 0);  /* Timeout */
        rsp_buffer_push(rsp, 0);  /* Timeout */
        break;

    case HIOMAP_C_GET_FLASH_INFO:
        rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) & 0xFF);
        rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) >> 8);
        rsp_buffer_push(rsp, 0x01);  /* erase size */
        rsp_buffer_push(rsp, 0x00);  /* erase size */
        break;

    case HIOMAP_C_CREATE_READ_WINDOW:
        readonly = true;
        /* Fall through */

    case HIOMAP_C_CREATE_WRITE_WINDOW:
        memory_region_set_readonly(&pnor->mmio, readonly);
        memory_region_set_enabled(&pnor->mmio, true);

        rsp_buffer_push(rsp, bytes_to_blocks(pnor_addr) & 0xFF);
        rsp_buffer_push(rsp, bytes_to_blocks(pnor_addr) >> 8);
        rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) & 0xFF);
        rsp_buffer_push(rsp, bytes_to_blocks(pnor_size) >> 8);
        rsp_buffer_push(rsp, 0x00); /* offset */
        rsp_buffer_push(rsp, 0x00); /* offset */
        break;

    case HIOMAP_C_CLOSE_WINDOW:
        memory_region_set_enabled(&pnor->mmio, false);
        break;

    case HIOMAP_C_DEVICE_NAME:
    case HIOMAP_C_RESET:
    case HIOMAP_C_LOCK:
    default:
        qemu_log_mask(LOG_GUEST_ERROR, "HIOMAP: unknow command %02X\n", cmd[2]);
        break;
    }
}

#define HIOMAP   0x5a

static const IPMICmdHandler hiomap_cmds[] = {
    [HIOMAP] = { hiomap_cmd, 3 },
};

static const IPMINetfn hiomap_netfn = {
    .cmd_nums = ARRAY_SIZE(hiomap_cmds),
    .cmd_handlers = hiomap_cmds
};

int pnv_bmc_hiomap(IPMIBmc *bmc)
{
    return ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(bmc),
                                   IPMI_NETFN_OEM, &hiomap_netfn);
}
+13 −0
Original line number Diff line number Diff line
@@ -810,6 +810,7 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
    ISABus *isa_bus;
    qemu_irq *irqs;
    qemu_irq_handler handler;
    PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());

    /* let isa_bus_new() create its own bridge on SysBus otherwise
     * devices speficied on the command line won't find the bus and
@@ -834,5 +835,17 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
    irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS);

    isa_bus_irqs(isa_bus, irqs);

    /*
     * TODO: Map PNOR on the LPC FW address space on demand ?
     */
    memory_region_add_subregion(&lpc->isa_fw, PNOR_SPI_OFFSET,
                                &pnv->pnor->mmio);
    /*
     * Start disabled. The HIOMAP protocol will activate the mapping
     * with HIOMAP_C_CREATE_WRITE_WINDOW
     */
    memory_region_set_enabled(&pnv->pnor->mmio, false);

    return isa_bus;
}
+1 −0
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ static inline bool pnv_is_power9(PnvMachineState *pnv)
 */
void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt);
void pnv_bmc_powerdown(IPMIBmc *bmc);
int pnv_bmc_hiomap(IPMIBmc *bmc);

/*
 * POWER8 MMIO base addresses
+5 −0
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@
#ifndef _PPC_PNV_PNOR_H
#define _PPC_PNV_PNOR_H

/*
 * PNOR offset on the LPC FW address space
 */
#define PNOR_SPI_OFFSET         0x0c000000UL

#define TYPE_PNV_PNOR  "pnv-pnor"
#define PNV_PNOR(obj)  OBJECT_CHECK(PnvPnor, (obj), TYPE_PNV_PNOR)