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

Configure Feed

Select the types of activity you want to include in your feed.

PCI: endpoint: Add pci_epf_assign_bar_space() API

Add pci_epf_assign_bar_space() API to allow setting any MMIO address as
the BAR memory space, such as an MSI message base address.

This API also conforms to the BAR base address and size alignment
restrictions enforced by the PCI spec r6.0, sec 7.5.1.2.1.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
[mani: removed unused epc var, reworded kdoc, comments and description]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20251015-vntb_msi_doorbell-v6-3-9230298b1910@nxp.com

authored by

Frank Li and committed by
Manivannan Sadhasivam
0bfc6758 f71e2b67

+83
+77
drivers/pci/endpoint/pci-epf-core.c
··· 346 346 } 347 347 EXPORT_SYMBOL_GPL(pci_epf_alloc_space); 348 348 349 + /** 350 + * pci_epf_assign_bar_space() - Assign PCI EPF BAR space 351 + * @epf: EPF device to assign the BAR memory 352 + * @size: Size of the memory that has to be assigned 353 + * @bar: BAR number for which the memory is assigned 354 + * @epc_features: Features provided by the EPC specific to this EPF 355 + * @type: Identifies if the assignment is for primary EPC or secondary EPC 356 + * @bar_addr: Address to be assigned for the @bar 357 + * 358 + * Invoke to assign memory for the PCI EPF BAR. 359 + * Flag PCI_BASE_ADDRESS_MEM_TYPE_64 will automatically get set if the BAR 360 + * can only be a 64-bit BAR, or if the requested size is larger than 2 GB. 361 + */ 362 + int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size, 363 + enum pci_barno bar, 364 + const struct pci_epc_features *epc_features, 365 + enum pci_epc_interface_type type, 366 + dma_addr_t bar_addr) 367 + { 368 + size_t bar_size, aligned_mem_size; 369 + struct pci_epf_bar *epf_bar; 370 + dma_addr_t limit; 371 + int pos; 372 + 373 + if (!size) 374 + return -EINVAL; 375 + 376 + limit = bar_addr + size - 1; 377 + 378 + /* 379 + * Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 380 + * bar_addr: U U U U U U 0 X X X X X X X X X 381 + * limit: U U U U U U 1 X X X X X X X X X 382 + * 383 + * bar_addr^limit 0 0 0 0 0 0 1 X X X X X X X X X 384 + * 385 + * U: unchanged address bits in range [bar_addr, limit] 386 + * X: bit 0 or 1 387 + * 388 + * (bar_addr^limit) & BIT_ULL(pos) will find the first set bit from MSB 389 + * (pos). And value of (2 ^ pos) should be able to cover the BAR range. 390 + */ 391 + for (pos = 8 * sizeof(dma_addr_t) - 1; pos > 0; pos--) 392 + if ((limit ^ bar_addr) & BIT_ULL(pos)) 393 + break; 394 + 395 + if (pos == 8 * sizeof(dma_addr_t) - 1) 396 + return -EINVAL; 397 + 398 + bar_size = BIT_ULL(pos + 1); 399 + if (pci_epf_get_required_bar_size(epf, &bar_size, &aligned_mem_size, 400 + bar, epc_features, type)) 401 + return -ENOMEM; 402 + 403 + if (type == PRIMARY_INTERFACE) 404 + epf_bar = epf->bar; 405 + else 406 + epf_bar = epf->sec_epc_bar; 407 + 408 + epf_bar[bar].phys_addr = ALIGN_DOWN(bar_addr, aligned_mem_size); 409 + 410 + if (epf_bar[bar].phys_addr + bar_size < limit) 411 + return -ENOMEM; 412 + 413 + epf_bar[bar].addr = NULL; 414 + epf_bar[bar].size = bar_size; 415 + epf_bar[bar].mem_size = aligned_mem_size; 416 + epf_bar[bar].barno = bar; 417 + if (upper_32_bits(size) || epc_features->bar[bar].only_64bit) 418 + epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; 419 + else 420 + epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_32; 421 + 422 + return 0; 423 + } 424 + EXPORT_SYMBOL_GPL(pci_epf_assign_bar_space); 425 + 349 426 static void pci_epf_remove_cfs(struct pci_epf_driver *driver) 350 427 { 351 428 struct config_group *group, *tmp;
+6
include/linux/pci-epf.h
··· 242 242 void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar, 243 243 enum pci_epc_interface_type type); 244 244 245 + int pci_epf_assign_bar_space(struct pci_epf *epf, size_t size, 246 + enum pci_barno bar, 247 + const struct pci_epc_features *epc_features, 248 + enum pci_epc_interface_type type, 249 + dma_addr_t bar_addr); 250 + 245 251 int pci_epf_align_inbound_addr(struct pci_epf *epf, enum pci_barno bar, 246 252 u64 addr, dma_addr_t *base, size_t *off); 247 253 int pci_epf_bind(struct pci_epf *epf);