brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 87493f9 Raw
188 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2015, Linaro Limited, Shannon Zhao4 */5 6#include <linux/platform_device.h>7#include <linux/acpi.h>8#include <xen/xen.h>9#include <xen/page.h>10#include <xen/interface/memory.h>11#include <asm/xen/hypervisor.h>12#include <asm/xen/hypercall.h>13 14static int xen_unmap_device_mmio(const struct resource *resources,15				 unsigned int count)16{17	unsigned int i, j, nr;18	int rc = 0;19	const struct resource *r;20	struct xen_remove_from_physmap xrp;21 22	for (i = 0; i < count; i++) {23		r = &resources[i];24		nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);25		if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))26			continue;27 28		for (j = 0; j < nr; j++) {29			xrp.domid = DOMID_SELF;30			xrp.gpfn = XEN_PFN_DOWN(r->start) + j;31			rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap,32						  &xrp);33			if (rc)34				return rc;35		}36	}37 38	return rc;39}40 41static int xen_map_device_mmio(const struct resource *resources,42			       unsigned int count)43{44	unsigned int i, j, nr;45	int rc = 0;46	const struct resource *r;47	xen_pfn_t *gpfns;48	xen_ulong_t *idxs;49	int *errs;50 51	for (i = 0; i < count; i++) {52		struct xen_add_to_physmap_range xatp = {53			.domid = DOMID_SELF,54			.space = XENMAPSPACE_dev_mmio55		};56 57		r = &resources[i];58		nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);59		if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))60			continue;61 62		gpfns = kcalloc(nr, sizeof(xen_pfn_t), GFP_KERNEL);63		idxs = kcalloc(nr, sizeof(xen_ulong_t), GFP_KERNEL);64		errs = kcalloc(nr, sizeof(int), GFP_KERNEL);65		if (!gpfns || !idxs || !errs) {66			kfree(gpfns);67			kfree(idxs);68			kfree(errs);69			rc = -ENOMEM;70			goto unmap;71		}72 73		for (j = 0; j < nr; j++) {74			/*75			 * The regions are always mapped 1:1 to DOM0 and this is76			 * fine because the memory map for DOM0 is the same as77			 * the host (except for the RAM).78			 */79			gpfns[j] = XEN_PFN_DOWN(r->start) + j;80			idxs[j] = XEN_PFN_DOWN(r->start) + j;81		}82 83		xatp.size = nr;84 85		set_xen_guest_handle(xatp.gpfns, gpfns);86		set_xen_guest_handle(xatp.idxs, idxs);87		set_xen_guest_handle(xatp.errs, errs);88 89		rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);90		kfree(gpfns);91		kfree(idxs);92		kfree(errs);93		if (rc)94			goto unmap;95	}96 97	return rc;98 99unmap:100	xen_unmap_device_mmio(resources, i);101	return rc;102}103 104static int xen_platform_notifier(struct notifier_block *nb,105				 unsigned long action, void *data)106{107	struct platform_device *pdev = to_platform_device(data);108	int r = 0;109 110	if (pdev->num_resources == 0 || pdev->resource == NULL)111		return NOTIFY_OK;112 113	switch (action) {114	case BUS_NOTIFY_ADD_DEVICE:115		r = xen_map_device_mmio(pdev->resource, pdev->num_resources);116		break;117	case BUS_NOTIFY_DEL_DEVICE:118		r = xen_unmap_device_mmio(pdev->resource, pdev->num_resources);119		break;120	default:121		return NOTIFY_DONE;122	}123	if (r)124		dev_err(&pdev->dev, "Platform: Failed to %s device %s MMIO!\n",125			action == BUS_NOTIFY_ADD_DEVICE ? "map" :126			(action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),127			pdev->name);128 129	return NOTIFY_OK;130}131 132static struct notifier_block platform_device_nb = {133	.notifier_call = xen_platform_notifier,134};135 136static int __init register_xen_platform_notifier(void)137{138	if (!xen_initial_domain() || acpi_disabled)139		return 0;140 141	return bus_register_notifier(&platform_bus_type, &platform_device_nb);142}143 144arch_initcall(register_xen_platform_notifier);145 146#ifdef CONFIG_ARM_AMBA147#include <linux/amba/bus.h>148 149static int xen_amba_notifier(struct notifier_block *nb,150			     unsigned long action, void *data)151{152	struct amba_device *adev = to_amba_device(data);153	int r = 0;154 155	switch (action) {156	case BUS_NOTIFY_ADD_DEVICE:157		r = xen_map_device_mmio(&adev->res, 1);158		break;159	case BUS_NOTIFY_DEL_DEVICE:160		r = xen_unmap_device_mmio(&adev->res, 1);161		break;162	default:163		return NOTIFY_DONE;164	}165	if (r)166		dev_err(&adev->dev, "AMBA: Failed to %s device %s MMIO!\n",167			action == BUS_NOTIFY_ADD_DEVICE ? "map" :168			(action == BUS_NOTIFY_DEL_DEVICE ? "unmap" : "?"),169			adev->dev.init_name);170 171	return NOTIFY_OK;172}173 174static struct notifier_block amba_device_nb = {175	.notifier_call = xen_amba_notifier,176};177 178static int __init register_xen_amba_notifier(void)179{180	if (!xen_initial_domain() || acpi_disabled)181		return 0;182 183	return bus_register_notifier(&amba_bustype, &amba_device_nb);184}185 186arch_initcall(register_xen_amba_notifier);187#endif188