brintos

brintos / linux-shallow public Read only

0
0
Text · 18.7 KiB · b11e401 Raw
759 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PCI Backend Xenbus Setup - handles setup with frontend and xend4 *5 *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#include <linux/moduleparam.h>11#include <linux/init.h>12#include <linux/list.h>13#include <linux/vmalloc.h>14#include <linux/workqueue.h>15#include <xen/xenbus.h>16#include <xen/events.h>17#include <xen/pci.h>18#include "pciback.h"19 20#define INVALID_EVTCHN_IRQ  (-1)21 22static bool __read_mostly passthrough;23module_param(passthrough, bool, S_IRUGO);24MODULE_PARM_DESC(passthrough,25	"Option to specify how to export PCI topology to guest:\n"\26	" 0 - (default) Hide the true PCI topology and makes the frontend\n"\27	"   there is a single PCI bus with only the exported devices on it.\n"\28	"   For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\29	"   while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\30	" 1 - Passthrough provides a real view of the PCI topology to the\n"\31	"   frontend (for example, a device at 06:01.b will still appear at\n"\32	"   06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\33	"   exposed PCI devices to its driver domains. This may be required\n"\34	"   for drivers which depend on finding their hardware in certain\n"\35	"   bus/slot locations.");36 37static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)38{39	struct xen_pcibk_device *pdev;40 41	pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL);42	if (pdev == NULL)43		goto out;44	dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);45 46	pdev->xdev = xdev;47 48	mutex_init(&pdev->dev_lock);49 50	pdev->sh_info = NULL;51	pdev->evtchn_irq = INVALID_EVTCHN_IRQ;52	pdev->be_watching = 0;53 54	INIT_WORK(&pdev->op_work, xen_pcibk_do_op);55 56	if (xen_pcibk_init_devices(pdev)) {57		kfree(pdev);58		pdev = NULL;59	}60 61	dev_set_drvdata(&xdev->dev, pdev);62 63out:64	return pdev;65}66 67static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev)68{69	mutex_lock(&pdev->dev_lock);70	/* Ensure the guest can't trigger our handler before removing devices */71	if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {72		unbind_from_irqhandler(pdev->evtchn_irq, pdev);73		pdev->evtchn_irq = INVALID_EVTCHN_IRQ;74	}75 76	/* If the driver domain started an op, make sure we complete it77	 * before releasing the shared memory */78 79	flush_work(&pdev->op_work);80 81	if (pdev->sh_info != NULL) {82		xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);83		pdev->sh_info = NULL;84	}85	mutex_unlock(&pdev->dev_lock);86}87 88static void free_pdev(struct xen_pcibk_device *pdev)89{90	if (pdev->be_watching) {91		unregister_xenbus_watch(&pdev->be_watch);92		pdev->be_watching = 0;93	}94 95	xen_pcibk_disconnect(pdev);96 97	/* N.B. This calls pcistub_put_pci_dev which does the FLR on all98	 * of the PCIe devices. */99	xen_pcibk_release_devices(pdev);100 101	dev_set_drvdata(&pdev->xdev->dev, NULL);102	pdev->xdev = NULL;103 104	kfree(pdev);105}106 107static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref,108			     evtchn_port_t remote_evtchn)109{110	int err = 0;111	void *vaddr;112 113	dev_dbg(&pdev->xdev->dev,114		"Attaching to frontend resources - gnt_ref=%d evtchn=%u\n",115		gnt_ref, remote_evtchn);116 117	err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr);118	if (err < 0) {119		xenbus_dev_fatal(pdev->xdev, err,120				"Error mapping other domain page in ours.");121		goto out;122	}123 124	pdev->sh_info = vaddr;125 126	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(127		pdev->xdev, remote_evtchn, xen_pcibk_handle_event,128		0, DRV_NAME, pdev);129	if (err < 0) {130		xenbus_dev_fatal(pdev->xdev, err,131				 "Error binding event channel to IRQ");132		goto out;133	}134	pdev->evtchn_irq = err;135	err = 0;136 137	dev_dbg(&pdev->xdev->dev, "Attached!\n");138out:139	return err;140}141 142static int xen_pcibk_attach(struct xen_pcibk_device *pdev)143{144	int err = 0;145	int gnt_ref;146	evtchn_port_t remote_evtchn;147	char *magic = NULL;148 149 150	mutex_lock(&pdev->dev_lock);151	/* Make sure we only do this setup once */152	if (xenbus_read_driver_state(pdev->xdev->nodename) !=153	    XenbusStateInitialised)154		goto out;155 156	/* Wait for frontend to state that it has published the configuration */157	if (xenbus_read_driver_state(pdev->xdev->otherend) !=158	    XenbusStateInitialised)159		goto out;160 161	dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");162 163	err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,164			    "pci-op-ref", "%u", &gnt_ref,165			    "event-channel", "%u", &remote_evtchn,166			    "magic", NULL, &magic, NULL);167	if (err) {168		/* If configuration didn't get read correctly, wait longer */169		xenbus_dev_fatal(pdev->xdev, err,170				 "Error reading configuration from frontend");171		goto out;172	}173 174	if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {175		xenbus_dev_fatal(pdev->xdev, -EFAULT,176				 "version mismatch (%s/%s) with pcifront - "177				 "halting " DRV_NAME,178				 magic, XEN_PCI_MAGIC);179		err = -EFAULT;180		goto out;181	}182 183	err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn);184	if (err)185		goto out;186 187	dev_dbg(&pdev->xdev->dev, "Connecting...\n");188 189	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);190	if (err)191		xenbus_dev_fatal(pdev->xdev, err,192				 "Error switching to connected state!");193 194	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);195out:196	mutex_unlock(&pdev->dev_lock);197 198	kfree(magic);199 200	return err;201}202 203static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev,204				   unsigned int domain, unsigned int bus,205				   unsigned int devfn, unsigned int devid)206{207	int err;208	int len;209	char str[64];210 211	len = snprintf(str, sizeof(str), "vdev-%d", devid);212	if (unlikely(len >= (sizeof(str) - 1))) {213		err = -ENOMEM;214		goto out;215	}216 217	/* Note: The PV protocol uses %02x, don't change it */218	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,219			    "%04x:%02x:%02x.%02x", domain, bus,220			    PCI_SLOT(devfn), PCI_FUNC(devfn));221 222out:223	return err;224}225 226static int xen_pcibk_export_device(struct xen_pcibk_device *pdev,227				 int domain, int bus, int slot, int func,228				 int devid)229{230	struct pci_dev *dev;231	int err = 0;232 233	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",234		domain, bus, slot, func);235 236	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);237	if (!dev) {238		err = -EINVAL;239		xenbus_dev_fatal(pdev->xdev, err,240				 "Couldn't locate PCI device "241				 "(%04x:%02x:%02x.%d)! "242				 "perhaps already in-use?",243				 domain, bus, slot, func);244		goto out;245	}246 247	err = xen_pcibk_add_pci_dev(pdev, dev, devid,248				    xen_pcibk_publish_pci_dev);249	if (err)250		goto out;251 252	dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);253	if (xen_register_device_domain_owner(dev,254					     pdev->xdev->otherend_id) != 0) {255		dev_err(&dev->dev, "Stealing ownership from dom%d.\n",256			xen_find_device_domain_owner(dev));257		xen_unregister_device_domain_owner(dev);258		xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);259	}260 261	/* TODO: It'd be nice to export a bridge and have all of its children262	 * get exported with it. This may be best done in xend (which will263	 * have to calculate resource usage anyway) but we probably want to264	 * put something in here to ensure that if a bridge gets given to a265	 * driver domain, that all devices under that bridge are not given266	 * to other driver domains (as he who controls the bridge can disable267	 * it and stop the other devices from working).268	 */269out:270	return err;271}272 273static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,274				 int domain, int bus, int slot, int func)275{276	int err = 0;277	struct pci_dev *dev;278 279	dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",280		domain, bus, slot, func);281 282	dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));283	if (!dev) {284		err = -EINVAL;285		dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "286			"(%04x:%02x:%02x.%d)! not owned by this domain\n",287			domain, bus, slot, func);288		goto out;289	}290 291	dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);292	xen_unregister_device_domain_owner(dev);293 294	/* N.B. This ends up calling pcistub_put_pci_dev which ends up295	 * doing the FLR. */296	xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */);297 298out:299	return err;300}301 302static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev,303				    unsigned int domain, unsigned int bus)304{305	unsigned int d, b;306	int i, root_num, len, err;307	char str[64];308 309	dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");310 311	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,312			   "root_num", "%d", &root_num);313	if (err == 0 || err == -ENOENT)314		root_num = 0;315	else if (err < 0)316		goto out;317 318	/* Verify that we haven't already published this pci root */319	for (i = 0; i < root_num; i++) {320		len = snprintf(str, sizeof(str), "root-%d", i);321		if (unlikely(len >= (sizeof(str) - 1))) {322			err = -ENOMEM;323			goto out;324		}325 326		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,327				   str, "%x:%x", &d, &b);328		if (err < 0)329			goto out;330		if (err != 2) {331			err = -EINVAL;332			goto out;333		}334 335		if (d == domain && b == bus) {336			err = 0;337			goto out;338		}339	}340 341	len = snprintf(str, sizeof(str), "root-%d", root_num);342	if (unlikely(len >= (sizeof(str) - 1))) {343		err = -ENOMEM;344		goto out;345	}346 347	dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",348		root_num, domain, bus);349 350	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,351			    "%04x:%02x", domain, bus);352	if (err)353		goto out;354 355	err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,356			    "root_num", "%d", (root_num + 1));357 358out:359	return err;360}361 362static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev,363				 enum xenbus_state state)364{365	int err = 0;366	int num_devs;367	int domain, bus, slot, func;368	unsigned int substate;369	int i, len;370	char state_str[64];371	char dev_str[64];372 373 374	dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");375 376	mutex_lock(&pdev->dev_lock);377	if (xenbus_read_driver_state(pdev->xdev->nodename) != state)378		goto out;379 380	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",381			   &num_devs);382	if (err != 1) {383		if (err >= 0)384			err = -EINVAL;385		xenbus_dev_fatal(pdev->xdev, err,386				 "Error reading number of devices");387		goto out;388	}389 390	for (i = 0; i < num_devs; i++) {391		len = snprintf(state_str, sizeof(state_str), "state-%d", i);392		if (unlikely(len >= (sizeof(state_str) - 1))) {393			err = -ENOMEM;394			xenbus_dev_fatal(pdev->xdev, err,395					 "String overflow while reading "396					 "configuration");397			goto out;398		}399		substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str,400						XenbusStateUnknown);401 402		switch (substate) {403		case XenbusStateInitialising:404			dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);405 406			len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);407			if (unlikely(len >= (sizeof(dev_str) - 1))) {408				err = -ENOMEM;409				xenbus_dev_fatal(pdev->xdev, err,410						 "String overflow while "411						 "reading configuration");412				goto out;413			}414			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,415					   dev_str, "%x:%x:%x.%x",416					   &domain, &bus, &slot, &func);417			if (err < 0) {418				xenbus_dev_fatal(pdev->xdev, err,419						 "Error reading device "420						 "configuration");421				goto out;422			}423			if (err != 4) {424				err = -EINVAL;425				xenbus_dev_fatal(pdev->xdev, err,426						 "Error parsing pci device "427						 "configuration");428				goto out;429			}430 431			err = xen_pcibk_export_device(pdev, domain, bus, slot,432						    func, i);433			if (err)434				goto out;435 436			/* Publish pci roots. */437			err = xen_pcibk_publish_pci_roots(pdev,438						xen_pcibk_publish_pci_root);439			if (err) {440				xenbus_dev_fatal(pdev->xdev, err,441						 "Error while publish PCI root"442						 "buses for frontend");443				goto out;444			}445 446			err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,447					    state_str, "%d",448					    XenbusStateInitialised);449			if (err) {450				xenbus_dev_fatal(pdev->xdev, err,451						 "Error switching substate of "452						 "dev-%d\n", i);453				goto out;454			}455			break;456 457		case XenbusStateClosing:458			dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);459 460			len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);461			if (unlikely(len >= (sizeof(dev_str) - 1))) {462				err = -ENOMEM;463				xenbus_dev_fatal(pdev->xdev, err,464						 "String overflow while "465						 "reading configuration");466				goto out;467			}468			err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,469					   dev_str, "%x:%x:%x.%x",470					   &domain, &bus, &slot, &func);471			if (err < 0) {472				xenbus_dev_fatal(pdev->xdev, err,473						 "Error reading device "474						 "configuration");475				goto out;476			}477			if (err != 4) {478				err = -EINVAL;479				xenbus_dev_fatal(pdev->xdev, err,480						 "Error parsing pci device "481						 "configuration");482				goto out;483			}484 485			err = xen_pcibk_remove_device(pdev, domain, bus, slot,486						    func);487			if (err)488				goto out;489 490			/* TODO: If at some point we implement support for pci491			 * root hot-remove on pcifront side, we'll need to492			 * remove unnecessary xenstore nodes of pci roots here.493			 */494 495			break;496 497		default:498			break;499		}500	}501 502	if (state != XenbusStateReconfiguring)503		/* Make sure we only reconfigure once. */504		goto out;505 506	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);507	if (err) {508		xenbus_dev_fatal(pdev->xdev, err,509				 "Error switching to reconfigured state!");510		goto out;511	}512 513out:514	mutex_unlock(&pdev->dev_lock);515	return 0;516}517 518static void xen_pcibk_frontend_changed(struct xenbus_device *xdev,519				     enum xenbus_state fe_state)520{521	struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev);522 523	dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);524 525	switch (fe_state) {526	case XenbusStateInitialised:527		xen_pcibk_attach(pdev);528		break;529 530	case XenbusStateReconfiguring:531		xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring);532		break;533 534	case XenbusStateConnected:535		/* pcifront switched its state from reconfiguring to connected.536		 * Then switch to connected state.537		 */538		xenbus_switch_state(xdev, XenbusStateConnected);539		break;540 541	case XenbusStateClosing:542		xen_pcibk_disconnect(pdev);543		xenbus_switch_state(xdev, XenbusStateClosing);544		break;545 546	case XenbusStateClosed:547		xen_pcibk_disconnect(pdev);548		xenbus_switch_state(xdev, XenbusStateClosed);549		if (xenbus_dev_is_online(xdev))550			break;551		fallthrough;	/* if not online */552	case XenbusStateUnknown:553		dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");554		device_unregister(&xdev->dev);555		break;556 557	default:558		break;559	}560}561 562static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)563{564	/* Get configuration from xend (if available now) */565	int domain, bus, slot, func;566	int err = 0;567	int i, num_devs;568	char dev_str[64];569	char state_str[64];570 571	mutex_lock(&pdev->dev_lock);572	/* It's possible we could get the call to setup twice, so make sure573	 * we're not already connected.574	 */575	if (xenbus_read_driver_state(pdev->xdev->nodename) !=576	    XenbusStateInitWait)577		goto out;578 579	dev_dbg(&pdev->xdev->dev, "getting be setup\n");580 581	err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",582			   &num_devs);583	if (err != 1) {584		if (err >= 0)585			err = -EINVAL;586		xenbus_dev_fatal(pdev->xdev, err,587				 "Error reading number of devices");588		goto out;589	}590 591	for (i = 0; i < num_devs; i++) {592		int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);593		if (unlikely(l >= (sizeof(dev_str) - 1))) {594			err = -ENOMEM;595			xenbus_dev_fatal(pdev->xdev, err,596					 "String overflow while reading "597					 "configuration");598			goto out;599		}600 601		err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,602				   "%x:%x:%x.%x", &domain, &bus, &slot, &func);603		if (err < 0) {604			xenbus_dev_fatal(pdev->xdev, err,605					 "Error reading device configuration");606			goto out;607		}608		if (err != 4) {609			err = -EINVAL;610			xenbus_dev_fatal(pdev->xdev, err,611					 "Error parsing pci device "612					 "configuration");613			goto out;614		}615 616		err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i);617		if (err)618			goto out;619 620		/* Switch substate of this device. */621		l = snprintf(state_str, sizeof(state_str), "state-%d", i);622		if (unlikely(l >= (sizeof(state_str) - 1))) {623			err = -ENOMEM;624			xenbus_dev_fatal(pdev->xdev, err,625					 "String overflow while reading "626					 "configuration");627			goto out;628		}629		err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,630				    "%d", XenbusStateInitialised);631		if (err) {632			xenbus_dev_fatal(pdev->xdev, err, "Error switching "633					 "substate of dev-%d\n", i);634			goto out;635		}636	}637 638	err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root);639	if (err) {640		xenbus_dev_fatal(pdev->xdev, err,641				 "Error while publish PCI root buses "642				 "for frontend");643		goto out;644	}645 646	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);647	if (err)648		xenbus_dev_fatal(pdev->xdev, err,649				 "Error switching to initialised state!");650 651out:652	mutex_unlock(&pdev->dev_lock);653	if (!err)654		/* see if pcifront is already configured (if not, we'll wait) */655		xen_pcibk_attach(pdev);656	return err;657}658 659static void xen_pcibk_be_watch(struct xenbus_watch *watch,660			       const char *path, const char *token)661{662	struct xen_pcibk_device *pdev =663	    container_of(watch, struct xen_pcibk_device, be_watch);664 665	switch (xenbus_read_driver_state(pdev->xdev->nodename)) {666	case XenbusStateInitWait:667		xen_pcibk_setup_backend(pdev);668		break;669 670	case XenbusStateInitialised:671		/*672		 * We typically move to Initialised when the first device was673		 * added. Hence subsequent devices getting added may need674		 * reconfiguring.675		 */676		xen_pcibk_reconfigure(pdev, XenbusStateInitialised);677		break;678 679	default:680		break;681	}682}683 684static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,685				const struct xenbus_device_id *id)686{687	int err = 0;688	struct xen_pcibk_device *pdev = alloc_pdev(dev);689 690	if (pdev == NULL) {691		err = -ENOMEM;692		xenbus_dev_fatal(dev, err,693				 "Error allocating xen_pcibk_device struct");694		goto out;695	}696 697	/* wait for xend to configure us */698	err = xenbus_switch_state(dev, XenbusStateInitWait);699	if (err)700		goto out;701 702	/* watch the backend node for backend configuration information */703	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,704				NULL, xen_pcibk_be_watch);705	if (err)706		goto out;707 708	pdev->be_watching = 1;709 710	/* We need to force a call to our callback here in case711	 * xend already configured us!712	 */713	xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL);714 715out:716	return err;717}718 719static void xen_pcibk_xenbus_remove(struct xenbus_device *dev)720{721	struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);722 723	if (pdev != NULL)724		free_pdev(pdev);725}726 727static const struct xenbus_device_id xen_pcibk_ids[] = {728	{"pci"},729	{""},730};731 732static struct xenbus_driver xen_pcibk_driver = {733	.name                   = DRV_NAME,734	.ids                    = xen_pcibk_ids,735	.probe			= xen_pcibk_xenbus_probe,736	.remove			= xen_pcibk_xenbus_remove,737	.otherend_changed	= xen_pcibk_frontend_changed,738};739 740const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend;741 742int __init xen_pcibk_xenbus_register(void)743{744	if (!xen_pcibk_pv_support())745		return 0;746 747	xen_pcibk_backend = &xen_pcibk_vpci_backend;748	if (passthrough)749		xen_pcibk_backend = &xen_pcibk_passthrough_backend;750	pr_info("backend is %s\n", xen_pcibk_backend->name);751	return xenbus_register_backend(&xen_pcibk_driver);752}753 754void __exit xen_pcibk_xenbus_unregister(void)755{756	if (xen_pcibk_pv_support())757		xenbus_unregister_driver(&xen_pcibk_driver);758}759