Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI/P2PDMA: Introduce configfs/sysfs enable attribute helpers

Users of the P2PDMA infrastructure will typically need a way for the user
to tell the kernel to use P2P resources. Typically this will be a simple
on/off boolean operation but sometimes it may be desirable for the user to
specify the exact device to use for the P2P operation.

Add new helpers for attributes which take a boolean or a PCI device. Any
boolean as accepted by strtobool() turn P2P on or off (such as 'y', 'n',
'1', '0', etc). Specifying a full PCI device name/BDF will select the
specific device.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

authored by

Logan Gunthorpe and committed by
Bjorn Helgaas
2d7bc010 977196b8

+97
+82
drivers/pci/p2pdma.c
··· 8 8 * Copyright (c) 2018, Eideticom Inc. 9 9 */ 10 10 11 + #define pr_fmt(fmt) "pci-p2pdma: " fmt 12 + #include <linux/ctype.h> 11 13 #include <linux/pci-p2pdma.h> 12 14 #include <linux/module.h> 13 15 #include <linux/slab.h> ··· 723 721 return nents; 724 722 } 725 723 EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg); 724 + 725 + /** 726 + * pci_p2pdma_enable_store - parse a configfs/sysfs attribute store 727 + * to enable p2pdma 728 + * @page: contents of the value to be stored 729 + * @p2p_dev: returns the PCI device that was selected to be used 730 + * (if one was specified in the stored value) 731 + * @use_p2pdma: returns whether to enable p2pdma or not 732 + * 733 + * Parses an attribute value to decide whether to enable p2pdma. 734 + * The value can select a PCI device (using it's full BDF device 735 + * name) or a boolean (in any format strtobool() accepts). A false 736 + * value disables p2pdma, a true value expects the caller 737 + * to automatically find a compatible device and specifying a PCI device 738 + * expects the caller to use the specific provider. 739 + * 740 + * pci_p2pdma_enable_show() should be used as the show operation for 741 + * the attribute. 742 + * 743 + * Returns 0 on success 744 + */ 745 + int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev, 746 + bool *use_p2pdma) 747 + { 748 + struct device *dev; 749 + 750 + dev = bus_find_device_by_name(&pci_bus_type, NULL, page); 751 + if (dev) { 752 + *use_p2pdma = true; 753 + *p2p_dev = to_pci_dev(dev); 754 + 755 + if (!pci_has_p2pmem(*p2p_dev)) { 756 + pci_err(*p2p_dev, 757 + "PCI device has no peer-to-peer memory: %s\n", 758 + page); 759 + pci_dev_put(*p2p_dev); 760 + return -ENODEV; 761 + } 762 + 763 + return 0; 764 + } else if ((page[0] == '0' || page[0] == '1') && !iscntrl(page[1])) { 765 + /* 766 + * If the user enters a PCI device that doesn't exist 767 + * like "0000:01:00.1", we don't want strtobool to think 768 + * it's a '0' when it's clearly not what the user wanted. 769 + * So we require 0's and 1's to be exactly one character. 770 + */ 771 + } else if (!strtobool(page, use_p2pdma)) { 772 + return 0; 773 + } 774 + 775 + pr_err("No such PCI device: %.*s\n", (int)strcspn(page, "\n"), page); 776 + return -ENODEV; 777 + } 778 + EXPORT_SYMBOL_GPL(pci_p2pdma_enable_store); 779 + 780 + /** 781 + * pci_p2pdma_enable_show - show a configfs/sysfs attribute indicating 782 + * whether p2pdma is enabled 783 + * @page: contents of the stored value 784 + * @p2p_dev: the selected p2p device (NULL if no device is selected) 785 + * @use_p2pdma: whether p2pdme has been enabled 786 + * 787 + * Attributes that use pci_p2pdma_enable_store() should use this function 788 + * to show the value of the attribute. 789 + * 790 + * Returns 0 on success 791 + */ 792 + ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev, 793 + bool use_p2pdma) 794 + { 795 + if (!use_p2pdma) 796 + return sprintf(page, "0\n"); 797 + 798 + if (!p2p_dev) 799 + return sprintf(page, "1\n"); 800 + 801 + return sprintf(page, "%s\n", pci_name(p2p_dev)); 802 + } 803 + EXPORT_SYMBOL_GPL(pci_p2pdma_enable_show);
+15
include/linux/pci-p2pdma.h
··· 32 32 void pci_p2pmem_publish(struct pci_dev *pdev, bool publish); 33 33 int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, 34 34 enum dma_data_direction dir); 35 + int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev, 36 + bool *use_p2pdma); 37 + ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev, 38 + bool use_p2pdma); 35 39 #else /* CONFIG_PCI_P2PDMA */ 36 40 static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, 37 41 size_t size, u64 offset) ··· 85 81 struct scatterlist *sg, int nents, enum dma_data_direction dir) 86 82 { 87 83 return 0; 84 + } 85 + static inline int pci_p2pdma_enable_store(const char *page, 86 + struct pci_dev **p2p_dev, bool *use_p2pdma) 87 + { 88 + *use_p2pdma = false; 89 + return 0; 90 + } 91 + static inline ssize_t pci_p2pdma_enable_show(char *page, 92 + struct pci_dev *p2p_dev, bool use_p2pdma) 93 + { 94 + return sprintf(page, "none\n"); 88 95 } 89 96 #endif /* CONFIG_PCI_P2PDMA */ 90 97