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

PCI: endpoint: Add MSI-X interfaces

Add PCI_EPC_IRQ_MSIX type.

Add MSI-X callbacks signatures to the ops structure.

Add sysfs interface for set/get MSI-X capability maximum number.

Update documentation accordingly.

Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Acked-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Gustavo Pimentel and committed by
Lorenzo Pieralisi
8963106e 4e965ede

+93
+2
Documentation/PCI/endpoint/function/binding/pci-test.txt
··· 15 15 interrupt_pin : Should be 1 - INTA, 2 - INTB, 3 - INTC, 4 -INTD 16 16 msi_interrupts : Should be 1 to 32 depending on the number of MSI interrupts 17 17 to test 18 + msix_interrupts : Should be 1 to 2048 depending on the number of MSI-X 19 + interrupts to test
+24
drivers/pci/endpoint/pci-ep-cfs.c
··· 286 286 to_pci_epf_group(item)->epf->msi_interrupts); 287 287 } 288 288 289 + static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, 290 + const char *page, size_t len) 291 + { 292 + u16 val; 293 + int ret; 294 + 295 + ret = kstrtou16(page, 0, &val); 296 + if (ret) 297 + return ret; 298 + 299 + to_pci_epf_group(item)->epf->msix_interrupts = val; 300 + 301 + return len; 302 + } 303 + 304 + static ssize_t pci_epf_msix_interrupts_show(struct config_item *item, 305 + char *page) 306 + { 307 + return sprintf(page, "%d\n", 308 + to_pci_epf_group(item)->epf->msix_interrupts); 309 + } 310 + 289 311 PCI_EPF_HEADER_R(vendorid) 290 312 PCI_EPF_HEADER_W_u16(vendorid) 291 313 ··· 349 327 CONFIGFS_ATTR(pci_epf_, subsys_id); 350 328 CONFIGFS_ATTR(pci_epf_, interrupt_pin); 351 329 CONFIGFS_ATTR(pci_epf_, msi_interrupts); 330 + CONFIGFS_ATTR(pci_epf_, msix_interrupts); 352 331 353 332 static struct configfs_attribute *pci_epf_attrs[] = { 354 333 &pci_epf_attr_vendorid, ··· 363 340 &pci_epf_attr_subsys_id, 364 341 &pci_epf_attr_interrupt_pin, 365 342 &pci_epf_attr_msi_interrupts, 343 + &pci_epf_attr_msix_interrupts, 366 344 NULL, 367 345 }; 368 346
+57
drivers/pci/endpoint/pci-epc-core.c
··· 218 218 EXPORT_SYMBOL_GPL(pci_epc_set_msi); 219 219 220 220 /** 221 + * pci_epc_get_msix() - get the number of MSI-X interrupt numbers allocated 222 + * @epc: the EPC device to which MSI-X interrupts was requested 223 + * @func_no: the endpoint function number in the EPC device 224 + * 225 + * Invoke to get the number of MSI-X interrupts allocated by the RC 226 + */ 227 + int pci_epc_get_msix(struct pci_epc *epc, u8 func_no) 228 + { 229 + int interrupt; 230 + unsigned long flags; 231 + 232 + if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) 233 + return 0; 234 + 235 + if (!epc->ops->get_msix) 236 + return 0; 237 + 238 + spin_lock_irqsave(&epc->lock, flags); 239 + interrupt = epc->ops->get_msix(epc, func_no); 240 + spin_unlock_irqrestore(&epc->lock, flags); 241 + 242 + if (interrupt < 0) 243 + return 0; 244 + 245 + return interrupt + 1; 246 + } 247 + EXPORT_SYMBOL_GPL(pci_epc_get_msix); 248 + 249 + /** 250 + * pci_epc_set_msix() - set the number of MSI-X interrupt numbers required 251 + * @epc: the EPC device on which MSI-X has to be configured 252 + * @func_no: the endpoint function number in the EPC device 253 + * @interrupts: number of MSI-X interrupts required by the EPF 254 + * 255 + * Invoke to set the required number of MSI-X interrupts. 256 + */ 257 + int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts) 258 + { 259 + int ret; 260 + unsigned long flags; 261 + 262 + if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || 263 + interrupts < 1 || interrupts > 2048) 264 + return -EINVAL; 265 + 266 + if (!epc->ops->set_msix) 267 + return 0; 268 + 269 + spin_lock_irqsave(&epc->lock, flags); 270 + ret = epc->ops->set_msix(epc, func_no, interrupts - 1); 271 + spin_unlock_irqrestore(&epc->lock, flags); 272 + 273 + return ret; 274 + } 275 + EXPORT_SYMBOL_GPL(pci_epc_set_msix); 276 + 277 + /** 221 278 * pci_epc_unmap_addr() - unmap CPU address from PCI address 222 279 * @epc: the EPC device on which address is allocated 223 280 * @func_no: the endpoint function number in the EPC device
+9
include/linux/pci-epc.h
··· 17 17 PCI_EPC_IRQ_UNKNOWN, 18 18 PCI_EPC_IRQ_LEGACY, 19 19 PCI_EPC_IRQ_MSI, 20 + PCI_EPC_IRQ_MSIX, 20 21 }; 21 22 22 23 /** ··· 31 30 * capability register 32 31 * @get_msi: ops to get the number of MSI interrupts allocated by the RC from 33 32 * the MSI capability register 33 + * @set_msix: ops to set the requested number of MSI-X interrupts in the 34 + * MSI-X capability register 35 + * @get_msix: ops to get the number of MSI-X interrupts allocated by the RC 36 + * from the MSI-X capability register 34 37 * @raise_irq: ops to raise a legacy or MSI interrupt 35 38 * @start: ops to start the PCI link 36 39 * @stop: ops to stop the PCI link ··· 53 48 phys_addr_t addr); 54 49 int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 interrupts); 55 50 int (*get_msi)(struct pci_epc *epc, u8 func_no); 51 + int (*set_msix)(struct pci_epc *epc, u8 func_no, u16 interrupts); 52 + int (*get_msix)(struct pci_epc *epc, u8 func_no); 56 53 int (*raise_irq)(struct pci_epc *epc, u8 func_no, 57 54 enum pci_epc_irq_type type, u8 interrupt_num); 58 55 int (*start)(struct pci_epc *epc); ··· 151 144 phys_addr_t phys_addr); 152 145 int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts); 153 146 int pci_epc_get_msi(struct pci_epc *epc, u8 func_no); 147 + int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts); 148 + int pci_epc_get_msix(struct pci_epc *epc, u8 func_no); 154 149 int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, 155 150 enum pci_epc_irq_type type, u8 interrupt_num); 156 151 int pci_epc_start(struct pci_epc *epc);
+1
include/linux/pci-epf.h
··· 119 119 struct pci_epf_header *header; 120 120 struct pci_epf_bar bar[6]; 121 121 u8 msi_interrupts; 122 + u16 msix_interrupts; 122 123 u8 func_no; 123 124 124 125 struct pci_epc *epc;