From patchwork Wed Dec 17 21:10:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laszlo Ersek X-Patchwork-Id: 422368 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D80C5140081 for ; Thu, 18 Dec 2014 08:11:44 +1100 (AEDT) Received: from localhost ([::1]:51551 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y1Lsk-00044R-Rb for incoming@patchwork.ozlabs.org; Wed, 17 Dec 2014 16:11:42 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39531) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y1Ls2-0002he-MG for qemu-devel@nongnu.org; Wed, 17 Dec 2014 16:11:04 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Y1Lrw-0008FQ-HN for qemu-devel@nongnu.org; Wed, 17 Dec 2014 16:10:58 -0500 Received: from mx1.redhat.com ([209.132.183.28]:60400) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Y1Lrw-0008CA-AV for qemu-devel@nongnu.org; Wed, 17 Dec 2014 16:10:52 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sBHLAng6029369 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Wed, 17 Dec 2014 16:10:49 -0500 Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-31.ams2.redhat.com [10.36.116.31]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sBHLAHmK026713; Wed, 17 Dec 2014 16:10:45 -0500 From: Laszlo Ersek To: peter.maydell@linaro.org, qemu-devel@nongnu.org, rjones@redhat.com, drjones@redhat.com, lersek@redhat.com, pbonzini@redhat.com, agraf@suse.de Date: Wed, 17 Dec 2014 22:10:08 +0100 Message-Id: <1418850613-26821-7-git-send-email-lersek@redhat.com> In-Reply-To: <1418850613-26821-1-git-send-email-lersek@redhat.com> References: <1418850613-26821-1-git-send-email-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v5 06/11] fw_cfg_mem: introduce the "data_width" property X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The "data_width" property is capable of changing the maximum valid access size to the MMIO data register, and resizes the memory region similarly, at device realization time. The default value of "data_memwidth" is set so that we don't yet diverge from "fw_cfg_data_mem_ops". Most of the fw_cfg_mem users will stick with the default, and for them we should continue using the statically allocated "fw_cfg_data_mem_ops". This is beneficial for debugging because gdb can resolve pointers referencing static objects to the names of those objects. Signed-off-by: Laszlo Ersek --- Notes: v5: - the wide data register is restricted to the MMIO mapping now; no interference with the I/O port mapping [Laszlo] - the wide data ops aren't allocated separately with g_memdup() any longer [Alex, Peter] - the wide data register handles splitting / combining itself [Paolo, Peter] v4: - reject I/O port combining if data register is wider than 1 byte [Peter] v3: - new in v3 [Drew Jones] hw/nvram/fw_cfg.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 5ba49dd..80f846f 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -77,8 +77,10 @@ struct FWCfgMemState { /*< public >*/ MemoryRegion ctl_iomem, data_iomem; hwaddr ctl_addr, data_addr; + uint32_t data_width; + MemoryRegionOps wide_data_ops; }; #define JPG_FILE 0 #define BMP_FILE 1 @@ -284,15 +286,60 @@ static uint8_t fw_cfg_read(FWCfgState *s) static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr, unsigned size) { - return fw_cfg_read(opaque); + FWCfgState *s = opaque; + uint8_t buf[8]; + unsigned i; + + for (i = 0; i < size; ++i) { + buf[i] = fw_cfg_read(s); + } + switch (size) { + case 1: + return buf[0]; + case 2: + return lduw_he_p(buf); + case 4: + return (uint32_t)ldl_he_p(buf); + case 8: + return ldq_he_p(buf); + } + abort(); } static void fw_cfg_data_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - fw_cfg_write(opaque, (uint8_t)value); + FWCfgState *s = opaque; + uint8_t buf[8]; + unsigned i; + + switch (size) { + case 1: + buf[0] = value; + break; + case 2: + stw_he_p(buf, value); + break; + case 4: + stl_he_p(buf, value); + break; + case 8: + stq_he_p(buf, value); + break; + default: + abort(); + } + for (i = 0; i < size; ++i) { + fw_cfg_write(s, buf[i]); + } +} + +static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return addr == 0; } static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) @@ -343,8 +390,9 @@ static const MemoryRegionOps fw_cfg_data_mem_ops = { .endianness = DEVICE_BIG_ENDIAN, .valid = { .min_access_size = 1, .max_access_size = 1, + .accepts = fw_cfg_data_mem_valid, }, }; static const MemoryRegionOps fw_cfg_comb_mem_ops = { @@ -626,8 +674,10 @@ FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr) dev = qdev_create(NULL, TYPE_FW_CFG_MEM); qdev_prop_set_uint64(dev, "ctl_addr", ctl_addr); qdev_prop_set_uint64(dev, "data_addr", data_addr); + qdev_prop_set_uint32(dev, "data_width", + fw_cfg_data_mem_ops.valid.max_access_size); return fw_cfg_init1(dev); } @@ -686,24 +736,37 @@ static const TypeInfo fw_cfg_io_info = { static Property fw_cfg_mem_properties[] = { DEFINE_PROP_UINT64("ctl_addr", FWCfgMemState, ctl_addr, -1), DEFINE_PROP_UINT64("data_addr", FWCfgMemState, data_addr, -1), + DEFINE_PROP_UINT32("data_width", FWCfgMemState, data_width, -1), DEFINE_PROP_END_OF_LIST(), }; static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) { FWCfgMemState *s = FW_CFG_MEM(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops; memory_region_init_io(&s->ctl_iomem, OBJECT(s), &fw_cfg_ctl_mem_ops, FW_CFG(s), "fwcfg.ctl", FW_CFG_SIZE); sysbus_init_mmio(sbd, &s->ctl_iomem); sysbus_mmio_map(sbd, 0, s->ctl_addr); - memory_region_init_io(&s->data_iomem, OBJECT(s), &fw_cfg_data_mem_ops, - FW_CFG(s), "fwcfg.data", - fw_cfg_data_mem_ops.valid.max_access_size); + if (s->data_width > data_ops->valid.max_access_size) { + /* memberwise copy because the "old_mmio" member is const */ + s->wide_data_ops.read = data_ops->read; + s->wide_data_ops.write = data_ops->write; + s->wide_data_ops.endianness = data_ops->endianness; + s->wide_data_ops.valid = data_ops->valid; + s->wide_data_ops.impl = data_ops->impl; + + s->wide_data_ops.valid.max_access_size = s->data_width; + s->wide_data_ops.impl.max_access_size = s->data_width; + data_ops = &s->wide_data_ops; + } + memory_region_init_io(&s->data_iomem, OBJECT(s), data_ops, FW_CFG(s), + "fwcfg.data", data_ops->valid.max_access_size); sysbus_init_mmio(sbd, &s->data_iomem); sysbus_mmio_map(sbd, 1, s->data_addr); }