This interface driver is a helper driver allows other drivers to have a common interface with the Hyper-V PCI frontend driver.
Unified · Split
| @@ -7469,6 +7469,7 @@ F: drivers/hid/hid-hyperv.c · 7468 unmodified lines | ||
| 7469 | 7469 | F: drivers/hv/ |
| 7470 | 7470 | F: drivers/input/serio/hyperv-keyboard.c |
| 7471 | 7471 | F: drivers/pci/controller/pci-hyperv.c |
| 7472 | +F: drivers/pci/controller/pci-hyperv-intf.c | |
| 7472 | 7473 | F: drivers/net/hyperv/ |
| 7473 | 7474 | F: drivers/scsi/storvsc_drv.c |
| 7474 | 7475 | F: drivers/uio/uio_hv_generic.c |
| @@ -182,6 +182,7 @@ config PCI_LABEL · 181 unmodified lines | ||
| 182 | 182 | config PCI_HYPERV |
| 183 | 183 | tristate "Hyper-V PCI Frontend" |
| 184 | 184 | depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 |
| 185 | + select PCI_HYPERV_INTERFACE | |
| 185 | 186 | help |
| 186 | 187 | The PCI device frontend driver allows the kernel to import arbitrary |
| 187 | 188 | PCI devices from a PCI backend to support PCI driver domains. |
| @@ -281,5 +281,12 @@ config VMD · 280 unmodified lines | ||
| 281 | 281 | To compile this driver as a module, choose M here: the |
| 282 | 282 | module will be called vmd. |
| 283 | 283 | |
| 284 | +config PCI_HYPERV_INTERFACE | |
| 285 | + tristate "Hyper-V PCI Interface" | |
| 286 | + depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 | |
| 287 | + help | |
| 288 | + The Hyper-V PCI Interface is a helper driver allows other drivers to | |
| 289 | + have a common interface with the Hyper-V PCI frontend driver. | |
| 290 | + | |
| 284 | 291 | source "drivers/pci/controller/dwc/Kconfig" |
| 285 | 292 | endmenu |
| @@ -4,6 +4,7 @@ obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o · 3 unmodified lines | ||
| 4 | 4 | obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o |
| 5 | 5 | obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o |
| 6 | 6 | obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o |
| 7 | +obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o | |
| 7 | 8 | obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o |
| 8 | 9 | obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o |
| 9 | 10 | obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o |
| @@ -0,0 +1,67 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (c) Microsoft Corporation. | |
| 4 | + * | |
| 5 | + * Author: | |
| 6 | + * Haiyang Zhang <haiyangz@microsoft.com> | |
| 7 | + * | |
| 8 | + * This small module is a helper driver allows other drivers to | |
| 9 | + * have a common interface with the Hyper-V PCI frontend driver. | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 13 | + | |
| 14 | +#include <linux/kernel.h> | |
| 15 | +#include <linux/module.h> | |
| 16 | +#include <linux/hyperv.h> | |
| 17 | + | |
| 18 | +struct hyperv_pci_block_ops hvpci_block_ops; | |
| 19 | +EXPORT_SYMBOL_GPL(hvpci_block_ops); | |
| 20 | + | |
| 21 | +int hyperv_read_cfg_blk(struct pci_dev *dev, void *buf, unsigned int buf_len, | |
| 22 | + unsigned int block_id, unsigned int *bytes_returned) | |
| 23 | +{ | |
| 24 | + if (!hvpci_block_ops.read_block) | |
| 25 | + return -EOPNOTSUPP; | |
| 26 | + | |
| 27 | + return hvpci_block_ops.read_block(dev, buf, buf_len, block_id, | |
| 28 | + bytes_returned); | |
| 29 | +} | |
| 30 | +EXPORT_SYMBOL_GPL(hyperv_read_cfg_blk); | |
| 31 | + | |
| 32 | +int hyperv_write_cfg_blk(struct pci_dev *dev, void *buf, unsigned int len, | |
| 33 | + unsigned int block_id) | |
| 34 | +{ | |
| 35 | + if (!hvpci_block_ops.write_block) | |
| 36 | + return -EOPNOTSUPP; | |
| 37 | + | |
| 38 | + return hvpci_block_ops.write_block(dev, buf, len, block_id); | |
| 39 | +} | |
| 40 | +EXPORT_SYMBOL_GPL(hyperv_write_cfg_blk); | |
| 41 | + | |
| 42 | +int hyperv_reg_block_invalidate(struct pci_dev *dev, void *context, | |
| 43 | + void (*block_invalidate)(void *context, | |
| 44 | + u64 block_mask)) | |
| 45 | +{ | |
| 46 | + if (!hvpci_block_ops.reg_blk_invalidate) | |
| 47 | + return -EOPNOTSUPP; | |
| 48 | + | |
| 49 | + return hvpci_block_ops.reg_blk_invalidate(dev, context, | |
| 50 | + block_invalidate); | |
| 51 | +} | |
| 52 | +EXPORT_SYMBOL_GPL(hyperv_reg_block_invalidate); | |
| 53 | + | |
| 54 | +static void __exit exit_hv_pci_intf(void) | |
| 55 | +{ | |
| 56 | +} | |
| 57 | + | |
| 58 | +static int __init init_hv_pci_intf(void) | |
| 59 | +{ | |
| 60 | + return 0; | |
| 61 | +} | |
| 62 | + | |
| 63 | +module_init(init_hv_pci_intf); | |
| 64 | +module_exit(exit_hv_pci_intf); | |
| 65 | + | |
| 66 | +MODULE_DESCRIPTION("Hyper-V PCI Interface"); | |
| 67 | +MODULE_LICENSE("GPL v2"); | |
| @@ -983,7 +983,6 @@ int hv_read_config_block(struct pci_dev *pdev, void *buf, unsigned int len, · 982 unmodified lines | ||
| 983 | 983 | *bytes_returned = comp_pkt.bytes_returned; |
| 984 | 984 | return 0; |
| 985 | 985 | } |
| 986 | −EXPORT_SYMBOL(hv_read_config_block); | |
| 987 | 986 | |
| 988 | 987 | /** |
| 989 | 988 | * hv_pci_write_config_compl() - Invoked when a response packet for a write |
| @@ -1070,7 +1069,6 @@ int hv_write_config_block(struct pci_dev *pdev, void *buf, unsigned int len, · 80 unmodified lines | ||
| 1070 | 1069 | |
| 1071 | 1070 | return 0; |
| 1072 | 1071 | } |
| 1073 | −EXPORT_SYMBOL(hv_write_config_block); | |
| 1074 | 1072 | |
| 1075 | 1073 | /** |
| 1076 | 1074 | * hv_register_block_invalidate() - Invoked when a config block invalidation |
| @@ -1101,7 +1099,6 @@ int hv_register_block_invalidate(struct pci_dev *pdev, void *context, · 24 unmodified lines | ||
| 1101 | 1099 | return 0; |
| 1102 | 1100 | |
| 1103 | 1101 | } |
| 1104 | −EXPORT_SYMBOL(hv_register_block_invalidate); | |
| 1105 | 1102 | |
| 1106 | 1103 | /* Interrupt management hooks */ |
| 1107 | 1104 | static void hv_int_desc_free(struct hv_pci_dev *hpdev, |
| @@ -3045,10 +3042,19 @@ static struct hv_driver hv_pci_drv = { · 1937 unmodified lines | ||
| 3045 | 3042 | static void __exit exit_hv_pci_drv(void) |
| 3046 | 3043 | { |
| 3047 | 3044 | vmbus_driver_unregister(&hv_pci_drv); |
| 3045 | + | |
| 3046 | + hvpci_block_ops.read_block = NULL; | |
| 3047 | + hvpci_block_ops.write_block = NULL; | |
| 3048 | + hvpci_block_ops.reg_blk_invalidate = NULL; | |
| 3048 | 3049 | } |
| 3049 | 3050 | |
| 3050 | 3051 | static int __init init_hv_pci_drv(void) |
| 3051 | 3052 | { |
| 3053 | + /* Initialize PCI block r/w interface */ | |
| 3054 | + hvpci_block_ops.read_block = hv_read_config_block; | |
| 3055 | + hvpci_block_ops.write_block = hv_write_config_block; | |
| 3056 | + hvpci_block_ops.reg_blk_invalidate = hv_register_block_invalidate; | |
| 3057 | + | |
| 3052 | 3058 | return vmbus_driver_register(&hv_pci_drv); |
| 3053 | 3059 | } |
| 3054 | 3060 | |
| @@ -1579,18 +1579,32 @@ hv_pkt_iter_next(struct vmbus_channel *channel, · 1578 unmodified lines | ||
| 1579 | 1579 | pkt = hv_pkt_iter_next(channel, pkt)) |
| 1580 | 1580 | |
| 1581 | 1581 | /* |
| 1582 | − * Functions for passing data between SR-IOV PF and VF drivers. The VF driver | |
| 1582 | + * Interface for passing data between SR-IOV PF and VF drivers. The VF driver | |
| 1583 | 1583 | * sends requests to read and write blocks. Each block must be 128 bytes or |
| 1584 | 1584 | * smaller. Optionally, the VF driver can register a callback function which |
| 1585 | 1585 | * will be invoked when the host says that one or more of the first 64 block |
| 1586 | 1586 | * IDs is "invalid" which means that the VF driver should reread them. |
| 1587 | 1587 | */ |
| 1588 | 1588 | #define HV_CONFIG_BLOCK_SIZE_MAX 128 |
| 1589 | −int hv_read_config_block(struct pci_dev *dev, void *buf, unsigned int buf_len, | |
| 1590 | − unsigned int block_id, unsigned int *bytes_returned); | |
| 1591 | −int hv_write_config_block(struct pci_dev *dev, void *buf, unsigned int len, | |
| 1592 | − unsigned int block_id); | |
| 1593 | −int hv_register_block_invalidate(struct pci_dev *dev, void *context, | |
| 1594 | − void (*block_invalidate)(void *context, | |
| 1595 | − u64 block_mask)); | |
| 1589 | + | |
| 1590 | +int hyperv_read_cfg_blk(struct pci_dev *dev, void *buf, unsigned int buf_len, | |
| 1591 | + unsigned int block_id, unsigned int *bytes_returned); | |
| 1592 | +int hyperv_write_cfg_blk(struct pci_dev *dev, void *buf, unsigned int len, | |
| 1593 | + unsigned int block_id); | |
| 1594 | +int hyperv_reg_block_invalidate(struct pci_dev *dev, void *context, | |
| 1595 | + void (*block_invalidate)(void *context, | |
| 1596 | + u64 block_mask)); | |
| 1597 | + | |
| 1598 | +struct hyperv_pci_block_ops { | |
| 1599 | + int (*read_block)(struct pci_dev *dev, void *buf, unsigned int buf_len, | |
| 1600 | + unsigned int block_id, unsigned int *bytes_returned); | |
| 1601 | + int (*write_block)(struct pci_dev *dev, void *buf, unsigned int len, | |
| 1602 | + unsigned int block_id); | |
| 1603 | + int (*reg_blk_invalidate)(struct pci_dev *dev, void *context, | |
| 1604 | + void (*block_invalidate)(void *context, | |
| 1605 | + u64 block_mask)); | |
| 1606 | +}; | |
| 1607 | + | |
| 1608 | +extern struct hyperv_pci_block_ops hvpci_block_ops; | |
| 1609 | + | |
| 1596 | 1610 | #endif /* _HYPERV_H */ |