| .. | .. | 
|---|
| 40 | 40 |  	 * membars, in order to allow proper address translation during | 
|---|
| 41 | 41 |  	 * resource assignment to enable guest virtualization | 
|---|
| 42 | 42 |  	 */ | 
|---|
| 43 |  | -	VMD_FEAT_HAS_MEMBAR_SHADOW	= (1 << 0),  | 
|---|
 | 43 | +	VMD_FEAT_HAS_MEMBAR_SHADOW		= (1 << 0),  | 
|---|
| 44 | 44 |   | 
|---|
| 45 | 45 |  	/* | 
|---|
| 46 | 46 |  	 * Device may provide root port configuration information which limits | 
|---|
| 47 | 47 |  	 * bus numbering | 
|---|
| 48 | 48 |  	 */ | 
|---|
| 49 |  | -	VMD_FEAT_HAS_BUS_RESTRICTIONS	= (1 << 1),  | 
|---|
 | 49 | +	VMD_FEAT_HAS_BUS_RESTRICTIONS		= (1 << 1),  | 
|---|
 | 50 | +  | 
|---|
 | 51 | +	/*  | 
|---|
 | 52 | +	 * Device contains physical location shadow registers in  | 
|---|
 | 53 | +	 * vendor-specific capability space  | 
|---|
 | 54 | +	 */  | 
|---|
 | 55 | +	VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP	= (1 << 2),  | 
|---|
| 50 | 56 |  }; | 
|---|
| 51 | 57 |   | 
|---|
| 52 | 58 |  /* | 
|---|
| .. | .. | 
|---|
| 98 | 104 |  	struct irq_domain	*irq_domain; | 
|---|
| 99 | 105 |  	struct pci_bus		*bus; | 
|---|
| 100 | 106 |  	u8			busn_start; | 
|---|
| 101 |  | -  | 
|---|
| 102 |  | -#ifdef CONFIG_X86_DEV_DMA_OPS  | 
|---|
| 103 |  | -	struct dma_map_ops	dma_ops;  | 
|---|
| 104 |  | -	struct dma_domain	dma_domain;  | 
|---|
| 105 |  | -#endif  | 
|---|
| 106 | 107 |  }; | 
|---|
| 107 | 108 |   | 
|---|
| 108 | 109 |  static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus) | 
|---|
| .. | .. | 
|---|
| 297 | 298 |  	.chip		= &vmd_msi_controller, | 
|---|
| 298 | 299 |  }; | 
|---|
| 299 | 300 |   | 
|---|
| 300 |  | -#ifdef CONFIG_X86_DEV_DMA_OPS  | 
|---|
| 301 |  | -/*  | 
|---|
| 302 |  | - * VMD replaces the requester ID with its own.  DMA mappings for devices in a  | 
|---|
| 303 |  | - * VMD domain need to be mapped for the VMD, not the device requiring  | 
|---|
| 304 |  | - * the mapping.  | 
|---|
| 305 |  | - */  | 
|---|
| 306 |  | -static struct device *to_vmd_dev(struct device *dev)  | 
|---|
 | 301 | +static int vmd_create_irq_domain(struct vmd_dev *vmd)  | 
|---|
| 307 | 302 |  { | 
|---|
| 308 |  | -	struct pci_dev *pdev = to_pci_dev(dev);  | 
|---|
| 309 |  | -	struct vmd_dev *vmd = vmd_from_bus(pdev->bus);  | 
|---|
 | 303 | +	struct fwnode_handle *fn;  | 
|---|
| 310 | 304 |   | 
|---|
| 311 |  | -	return &vmd->dev->dev;  | 
|---|
 | 305 | +	fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);  | 
|---|
 | 306 | +	if (!fn)  | 
|---|
 | 307 | +		return -ENODEV;  | 
|---|
 | 308 | +  | 
|---|
 | 309 | +	vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, NULL);  | 
|---|
 | 310 | +	if (!vmd->irq_domain) {  | 
|---|
 | 311 | +		irq_domain_free_fwnode(fn);  | 
|---|
 | 312 | +		return -ENODEV;  | 
|---|
 | 313 | +	}  | 
|---|
 | 314 | +  | 
|---|
 | 315 | +	return 0;  | 
|---|
| 312 | 316 |  } | 
|---|
| 313 | 317 |   | 
|---|
| 314 |  | -static const struct dma_map_ops *vmd_dma_ops(struct device *dev)  | 
|---|
 | 318 | +static void vmd_remove_irq_domain(struct vmd_dev *vmd)  | 
|---|
| 315 | 319 |  { | 
|---|
| 316 |  | -	return get_dma_ops(to_vmd_dev(dev));  | 
|---|
 | 320 | +	if (vmd->irq_domain) {  | 
|---|
 | 321 | +		struct fwnode_handle *fn = vmd->irq_domain->fwnode;  | 
|---|
 | 322 | +  | 
|---|
 | 323 | +		irq_domain_remove(vmd->irq_domain);  | 
|---|
 | 324 | +		irq_domain_free_fwnode(fn);  | 
|---|
 | 325 | +	}  | 
|---|
| 317 | 326 |  } | 
|---|
| 318 |  | -  | 
|---|
| 319 |  | -static void *vmd_alloc(struct device *dev, size_t size, dma_addr_t *addr,  | 
|---|
| 320 |  | -		       gfp_t flag, unsigned long attrs)  | 
|---|
| 321 |  | -{  | 
|---|
| 322 |  | -	return vmd_dma_ops(dev)->alloc(to_vmd_dev(dev), size, addr, flag,  | 
|---|
| 323 |  | -				       attrs);  | 
|---|
| 324 |  | -}  | 
|---|
| 325 |  | -  | 
|---|
| 326 |  | -static void vmd_free(struct device *dev, size_t size, void *vaddr,  | 
|---|
| 327 |  | -		     dma_addr_t addr, unsigned long attrs)  | 
|---|
| 328 |  | -{  | 
|---|
| 329 |  | -	return vmd_dma_ops(dev)->free(to_vmd_dev(dev), size, vaddr, addr,  | 
|---|
| 330 |  | -				      attrs);  | 
|---|
| 331 |  | -}  | 
|---|
| 332 |  | -  | 
|---|
| 333 |  | -static int vmd_mmap(struct device *dev, struct vm_area_struct *vma,  | 
|---|
| 334 |  | -		    void *cpu_addr, dma_addr_t addr, size_t size,  | 
|---|
| 335 |  | -		    unsigned long attrs)  | 
|---|
| 336 |  | -{  | 
|---|
| 337 |  | -	return vmd_dma_ops(dev)->mmap(to_vmd_dev(dev), vma, cpu_addr, addr,  | 
|---|
| 338 |  | -				      size, attrs);  | 
|---|
| 339 |  | -}  | 
|---|
| 340 |  | -  | 
|---|
| 341 |  | -static int vmd_get_sgtable(struct device *dev, struct sg_table *sgt,  | 
|---|
| 342 |  | -			   void *cpu_addr, dma_addr_t addr, size_t size,  | 
|---|
| 343 |  | -			   unsigned long attrs)  | 
|---|
| 344 |  | -{  | 
|---|
| 345 |  | -	return vmd_dma_ops(dev)->get_sgtable(to_vmd_dev(dev), sgt, cpu_addr,  | 
|---|
| 346 |  | -					     addr, size, attrs);  | 
|---|
| 347 |  | -}  | 
|---|
| 348 |  | -  | 
|---|
| 349 |  | -static dma_addr_t vmd_map_page(struct device *dev, struct page *page,  | 
|---|
| 350 |  | -			       unsigned long offset, size_t size,  | 
|---|
| 351 |  | -			       enum dma_data_direction dir,  | 
|---|
| 352 |  | -			       unsigned long attrs)  | 
|---|
| 353 |  | -{  | 
|---|
| 354 |  | -	return vmd_dma_ops(dev)->map_page(to_vmd_dev(dev), page, offset, size,  | 
|---|
| 355 |  | -					  dir, attrs);  | 
|---|
| 356 |  | -}  | 
|---|
| 357 |  | -  | 
|---|
| 358 |  | -static void vmd_unmap_page(struct device *dev, dma_addr_t addr, size_t size,  | 
|---|
| 359 |  | -			   enum dma_data_direction dir, unsigned long attrs)  | 
|---|
| 360 |  | -{  | 
|---|
| 361 |  | -	vmd_dma_ops(dev)->unmap_page(to_vmd_dev(dev), addr, size, dir, attrs);  | 
|---|
| 362 |  | -}  | 
|---|
| 363 |  | -  | 
|---|
| 364 |  | -static int vmd_map_sg(struct device *dev, struct scatterlist *sg, int nents,  | 
|---|
| 365 |  | -		      enum dma_data_direction dir, unsigned long attrs)  | 
|---|
| 366 |  | -{  | 
|---|
| 367 |  | -	return vmd_dma_ops(dev)->map_sg(to_vmd_dev(dev), sg, nents, dir, attrs);  | 
|---|
| 368 |  | -}  | 
|---|
| 369 |  | -  | 
|---|
| 370 |  | -static void vmd_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,  | 
|---|
| 371 |  | -			 enum dma_data_direction dir, unsigned long attrs)  | 
|---|
| 372 |  | -{  | 
|---|
| 373 |  | -	vmd_dma_ops(dev)->unmap_sg(to_vmd_dev(dev), sg, nents, dir, attrs);  | 
|---|
| 374 |  | -}  | 
|---|
| 375 |  | -  | 
|---|
| 376 |  | -static void vmd_sync_single_for_cpu(struct device *dev, dma_addr_t addr,  | 
|---|
| 377 |  | -				    size_t size, enum dma_data_direction dir)  | 
|---|
| 378 |  | -{  | 
|---|
| 379 |  | -	vmd_dma_ops(dev)->sync_single_for_cpu(to_vmd_dev(dev), addr, size, dir);  | 
|---|
| 380 |  | -}  | 
|---|
| 381 |  | -  | 
|---|
| 382 |  | -static void vmd_sync_single_for_device(struct device *dev, dma_addr_t addr,  | 
|---|
| 383 |  | -				       size_t size, enum dma_data_direction dir)  | 
|---|
| 384 |  | -{  | 
|---|
| 385 |  | -	vmd_dma_ops(dev)->sync_single_for_device(to_vmd_dev(dev), addr, size,  | 
|---|
| 386 |  | -						 dir);  | 
|---|
| 387 |  | -}  | 
|---|
| 388 |  | -  | 
|---|
| 389 |  | -static void vmd_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,  | 
|---|
| 390 |  | -				int nents, enum dma_data_direction dir)  | 
|---|
| 391 |  | -{  | 
|---|
| 392 |  | -	vmd_dma_ops(dev)->sync_sg_for_cpu(to_vmd_dev(dev), sg, nents, dir);  | 
|---|
| 393 |  | -}  | 
|---|
| 394 |  | -  | 
|---|
| 395 |  | -static void vmd_sync_sg_for_device(struct device *dev, struct scatterlist *sg,  | 
|---|
| 396 |  | -				   int nents, enum dma_data_direction dir)  | 
|---|
| 397 |  | -{  | 
|---|
| 398 |  | -	vmd_dma_ops(dev)->sync_sg_for_device(to_vmd_dev(dev), sg, nents, dir);  | 
|---|
| 399 |  | -}  | 
|---|
| 400 |  | -  | 
|---|
| 401 |  | -static int vmd_mapping_error(struct device *dev, dma_addr_t addr)  | 
|---|
| 402 |  | -{  | 
|---|
| 403 |  | -	return vmd_dma_ops(dev)->mapping_error(to_vmd_dev(dev), addr);  | 
|---|
| 404 |  | -}  | 
|---|
| 405 |  | -  | 
|---|
| 406 |  | -static int vmd_dma_supported(struct device *dev, u64 mask)  | 
|---|
| 407 |  | -{  | 
|---|
| 408 |  | -	return vmd_dma_ops(dev)->dma_supported(to_vmd_dev(dev), mask);  | 
|---|
| 409 |  | -}  | 
|---|
| 410 |  | -  | 
|---|
| 411 |  | -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK  | 
|---|
| 412 |  | -static u64 vmd_get_required_mask(struct device *dev)  | 
|---|
| 413 |  | -{  | 
|---|
| 414 |  | -	return vmd_dma_ops(dev)->get_required_mask(to_vmd_dev(dev));  | 
|---|
| 415 |  | -}  | 
|---|
| 416 |  | -#endif  | 
|---|
| 417 |  | -  | 
|---|
| 418 |  | -static void vmd_teardown_dma_ops(struct vmd_dev *vmd)  | 
|---|
| 419 |  | -{  | 
|---|
| 420 |  | -	struct dma_domain *domain = &vmd->dma_domain;  | 
|---|
| 421 |  | -  | 
|---|
| 422 |  | -	if (get_dma_ops(&vmd->dev->dev))  | 
|---|
| 423 |  | -		del_dma_domain(domain);  | 
|---|
| 424 |  | -}  | 
|---|
| 425 |  | -  | 
|---|
| 426 |  | -#define ASSIGN_VMD_DMA_OPS(source, dest, fn)	\  | 
|---|
| 427 |  | -	do {					\  | 
|---|
| 428 |  | -		if (source->fn)			\  | 
|---|
| 429 |  | -			dest->fn = vmd_##fn;	\  | 
|---|
| 430 |  | -	} while (0)  | 
|---|
| 431 |  | -  | 
|---|
| 432 |  | -static void vmd_setup_dma_ops(struct vmd_dev *vmd)  | 
|---|
| 433 |  | -{  | 
|---|
| 434 |  | -	const struct dma_map_ops *source = get_dma_ops(&vmd->dev->dev);  | 
|---|
| 435 |  | -	struct dma_map_ops *dest = &vmd->dma_ops;  | 
|---|
| 436 |  | -	struct dma_domain *domain = &vmd->dma_domain;  | 
|---|
| 437 |  | -  | 
|---|
| 438 |  | -	domain->domain_nr = vmd->sysdata.domain;  | 
|---|
| 439 |  | -	domain->dma_ops = dest;  | 
|---|
| 440 |  | -  | 
|---|
| 441 |  | -	if (!source)  | 
|---|
| 442 |  | -		return;  | 
|---|
| 443 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, alloc);  | 
|---|
| 444 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, free);  | 
|---|
| 445 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, mmap);  | 
|---|
| 446 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, get_sgtable);  | 
|---|
| 447 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, map_page);  | 
|---|
| 448 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, unmap_page);  | 
|---|
| 449 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, map_sg);  | 
|---|
| 450 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, unmap_sg);  | 
|---|
| 451 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, sync_single_for_cpu);  | 
|---|
| 452 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, sync_single_for_device);  | 
|---|
| 453 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_cpu);  | 
|---|
| 454 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_device);  | 
|---|
| 455 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, mapping_error);  | 
|---|
| 456 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, dma_supported);  | 
|---|
| 457 |  | -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK  | 
|---|
| 458 |  | -	ASSIGN_VMD_DMA_OPS(source, dest, get_required_mask);  | 
|---|
| 459 |  | -#endif  | 
|---|
| 460 |  | -	add_dma_domain(domain);  | 
|---|
| 461 |  | -}  | 
|---|
| 462 |  | -#undef ASSIGN_VMD_DMA_OPS  | 
|---|
| 463 |  | -#else  | 
|---|
| 464 |  | -static void vmd_teardown_dma_ops(struct vmd_dev *vmd) {}  | 
|---|
| 465 |  | -static void vmd_setup_dma_ops(struct vmd_dev *vmd) {}  | 
|---|
| 466 |  | -#endif  | 
|---|
| 467 | 327 |   | 
|---|
| 468 | 328 |  static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus, | 
|---|
| 469 | 329 |  				  unsigned int devfn, int reg, int len) | 
|---|
| .. | .. | 
|---|
| 584 | 444 |  	return domain + 1; | 
|---|
| 585 | 445 |  } | 
|---|
| 586 | 446 |   | 
|---|
 | 447 | +static int vmd_get_phys_offsets(struct vmd_dev *vmd, bool native_hint,  | 
|---|
 | 448 | +				resource_size_t *offset1,  | 
|---|
 | 449 | +				resource_size_t *offset2)  | 
|---|
 | 450 | +{  | 
|---|
 | 451 | +	struct pci_dev *dev = vmd->dev;  | 
|---|
 | 452 | +	u64 phys1, phys2;  | 
|---|
 | 453 | +  | 
|---|
 | 454 | +	if (native_hint) {  | 
|---|
 | 455 | +		u32 vmlock;  | 
|---|
 | 456 | +		int ret;  | 
|---|
 | 457 | +  | 
|---|
 | 458 | +		ret = pci_read_config_dword(dev, PCI_REG_VMLOCK, &vmlock);  | 
|---|
 | 459 | +		if (ret || vmlock == ~0)  | 
|---|
 | 460 | +			return -ENODEV;  | 
|---|
 | 461 | +  | 
|---|
 | 462 | +		if (MB2_SHADOW_EN(vmlock)) {  | 
|---|
 | 463 | +			void __iomem *membar2;  | 
|---|
 | 464 | +  | 
|---|
 | 465 | +			membar2 = pci_iomap(dev, VMD_MEMBAR2, 0);  | 
|---|
 | 466 | +			if (!membar2)  | 
|---|
 | 467 | +				return -ENOMEM;  | 
|---|
 | 468 | +			phys1 = readq(membar2 + MB2_SHADOW_OFFSET);  | 
|---|
 | 469 | +			phys2 = readq(membar2 + MB2_SHADOW_OFFSET + 8);  | 
|---|
 | 470 | +			pci_iounmap(dev, membar2);  | 
|---|
 | 471 | +		} else  | 
|---|
 | 472 | +			return 0;  | 
|---|
 | 473 | +	} else {  | 
|---|
 | 474 | +		/* Hypervisor-Emulated Vendor-Specific Capability */  | 
|---|
 | 475 | +		int pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);  | 
|---|
 | 476 | +		u32 reg, regu;  | 
|---|
 | 477 | +  | 
|---|
 | 478 | +		pci_read_config_dword(dev, pos + 4, ®);  | 
|---|
 | 479 | +  | 
|---|
 | 480 | +		/* "SHDW" */  | 
|---|
 | 481 | +		if (pos && reg == 0x53484457) {  | 
|---|
 | 482 | +			pci_read_config_dword(dev, pos + 8, ®);  | 
|---|
 | 483 | +			pci_read_config_dword(dev, pos + 12, ®u);  | 
|---|
 | 484 | +			phys1 = (u64) regu << 32 | reg;  | 
|---|
 | 485 | +  | 
|---|
 | 486 | +			pci_read_config_dword(dev, pos + 16, ®);  | 
|---|
 | 487 | +			pci_read_config_dword(dev, pos + 20, ®u);  | 
|---|
 | 488 | +			phys2 = (u64) regu << 32 | reg;  | 
|---|
 | 489 | +		} else  | 
|---|
 | 490 | +			return 0;  | 
|---|
 | 491 | +	}  | 
|---|
 | 492 | +  | 
|---|
 | 493 | +	*offset1 = dev->resource[VMD_MEMBAR1].start -  | 
|---|
 | 494 | +			(phys1 & PCI_BASE_ADDRESS_MEM_MASK);  | 
|---|
 | 495 | +	*offset2 = dev->resource[VMD_MEMBAR2].start -  | 
|---|
 | 496 | +			(phys2 & PCI_BASE_ADDRESS_MEM_MASK);  | 
|---|
 | 497 | +  | 
|---|
 | 498 | +	return 0;  | 
|---|
 | 499 | +}  | 
|---|
 | 500 | +  | 
|---|
 | 501 | +static int vmd_get_bus_number_start(struct vmd_dev *vmd)  | 
|---|
 | 502 | +{  | 
|---|
 | 503 | +	struct pci_dev *dev = vmd->dev;  | 
|---|
 | 504 | +	u16 reg;  | 
|---|
 | 505 | +  | 
|---|
 | 506 | +	pci_read_config_word(dev, PCI_REG_VMCAP, ®);  | 
|---|
 | 507 | +	if (BUS_RESTRICT_CAP(reg)) {  | 
|---|
 | 508 | +		pci_read_config_word(dev, PCI_REG_VMCONFIG, ®);  | 
|---|
 | 509 | +  | 
|---|
 | 510 | +		switch (BUS_RESTRICT_CFG(reg)) {  | 
|---|
 | 511 | +		case 0:  | 
|---|
 | 512 | +			vmd->busn_start = 0;  | 
|---|
 | 513 | +			break;  | 
|---|
 | 514 | +		case 1:  | 
|---|
 | 515 | +			vmd->busn_start = 128;  | 
|---|
 | 516 | +			break;  | 
|---|
 | 517 | +		case 2:  | 
|---|
 | 518 | +			vmd->busn_start = 224;  | 
|---|
 | 519 | +			break;  | 
|---|
 | 520 | +		default:  | 
|---|
 | 521 | +			pci_err(dev, "Unknown Bus Offset Setting (%d)\n",  | 
|---|
 | 522 | +				BUS_RESTRICT_CFG(reg));  | 
|---|
 | 523 | +			return -ENODEV;  | 
|---|
 | 524 | +		}  | 
|---|
 | 525 | +	}  | 
|---|
 | 526 | +  | 
|---|
 | 527 | +	return 0;  | 
|---|
 | 528 | +}  | 
|---|
 | 529 | +  | 
|---|
 | 530 | +static irqreturn_t vmd_irq(int irq, void *data)  | 
|---|
 | 531 | +{  | 
|---|
 | 532 | +	struct vmd_irq_list *irqs = data;  | 
|---|
 | 533 | +	struct vmd_irq *vmdirq;  | 
|---|
 | 534 | +	int idx;  | 
|---|
 | 535 | +  | 
|---|
 | 536 | +	idx = srcu_read_lock(&irqs->srcu);  | 
|---|
 | 537 | +	list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)  | 
|---|
 | 538 | +		generic_handle_irq(vmdirq->virq);  | 
|---|
 | 539 | +	srcu_read_unlock(&irqs->srcu, idx);  | 
|---|
 | 540 | +  | 
|---|
 | 541 | +	return IRQ_HANDLED;  | 
|---|
 | 542 | +}  | 
|---|
 | 543 | +  | 
|---|
 | 544 | +static int vmd_alloc_irqs(struct vmd_dev *vmd)  | 
|---|
 | 545 | +{  | 
|---|
 | 546 | +	struct pci_dev *dev = vmd->dev;  | 
|---|
 | 547 | +	int i, err;  | 
|---|
 | 548 | +  | 
|---|
 | 549 | +	vmd->msix_count = pci_msix_vec_count(dev);  | 
|---|
 | 550 | +	if (vmd->msix_count < 0)  | 
|---|
 | 551 | +		return -ENODEV;  | 
|---|
 | 552 | +  | 
|---|
 | 553 | +	vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,  | 
|---|
 | 554 | +						PCI_IRQ_MSIX);  | 
|---|
 | 555 | +	if (vmd->msix_count < 0)  | 
|---|
 | 556 | +		return vmd->msix_count;  | 
|---|
 | 557 | +  | 
|---|
 | 558 | +	vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),  | 
|---|
 | 559 | +				 GFP_KERNEL);  | 
|---|
 | 560 | +	if (!vmd->irqs)  | 
|---|
 | 561 | +		return -ENOMEM;  | 
|---|
 | 562 | +  | 
|---|
 | 563 | +	for (i = 0; i < vmd->msix_count; i++) {  | 
|---|
 | 564 | +		err = init_srcu_struct(&vmd->irqs[i].srcu);  | 
|---|
 | 565 | +		if (err)  | 
|---|
 | 566 | +			return err;  | 
|---|
 | 567 | +  | 
|---|
 | 568 | +		INIT_LIST_HEAD(&vmd->irqs[i].irq_list);  | 
|---|
 | 569 | +		err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),  | 
|---|
 | 570 | +				       vmd_irq, IRQF_NO_THREAD,  | 
|---|
 | 571 | +				       "vmd", &vmd->irqs[i]);  | 
|---|
 | 572 | +		if (err)  | 
|---|
 | 573 | +			return err;  | 
|---|
 | 574 | +	}  | 
|---|
 | 575 | +  | 
|---|
 | 576 | +	return 0;  | 
|---|
 | 577 | +}  | 
|---|
 | 578 | +  | 
|---|
| 587 | 579 |  static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) | 
|---|
| 588 | 580 |  { | 
|---|
| 589 | 581 |  	struct pci_sysdata *sd = &vmd->sysdata; | 
|---|
| 590 |  | -	struct fwnode_handle *fn;  | 
|---|
| 591 | 582 |  	struct resource *res; | 
|---|
| 592 | 583 |  	u32 upper_bits; | 
|---|
| 593 | 584 |  	unsigned long flags; | 
|---|
| 594 | 585 |  	LIST_HEAD(resources); | 
|---|
| 595 | 586 |  	resource_size_t offset[2] = {0}; | 
|---|
| 596 | 587 |  	resource_size_t membar2_offset = 0x2000; | 
|---|
 | 588 | +	struct pci_bus *child;  | 
|---|
 | 589 | +	int ret;  | 
|---|
| 597 | 590 |   | 
|---|
| 598 | 591 |  	/* | 
|---|
| 599 | 592 |  	 * Shadow registers may exist in certain VMD device ids which allow | 
|---|
| .. | .. | 
|---|
| 602 | 595 |  	 * or 0, depending on an enable bit in the VMD device. | 
|---|
| 603 | 596 |  	 */ | 
|---|
| 604 | 597 |  	if (features & VMD_FEAT_HAS_MEMBAR_SHADOW) { | 
|---|
| 605 |  | -		u32 vmlock;  | 
|---|
| 606 |  | -		int ret;  | 
|---|
| 607 |  | -  | 
|---|
| 608 | 598 |  		membar2_offset = MB2_SHADOW_OFFSET + MB2_SHADOW_SIZE; | 
|---|
| 609 |  | -		ret = pci_read_config_dword(vmd->dev, PCI_REG_VMLOCK, &vmlock);  | 
|---|
| 610 |  | -		if (ret || vmlock == ~0)  | 
|---|
| 611 |  | -			return -ENODEV;  | 
|---|
| 612 |  | -  | 
|---|
| 613 |  | -		if (MB2_SHADOW_EN(vmlock)) {  | 
|---|
| 614 |  | -			void __iomem *membar2;  | 
|---|
| 615 |  | -  | 
|---|
| 616 |  | -			membar2 = pci_iomap(vmd->dev, VMD_MEMBAR2, 0);  | 
|---|
| 617 |  | -			if (!membar2)  | 
|---|
| 618 |  | -				return -ENOMEM;  | 
|---|
| 619 |  | -			offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -  | 
|---|
| 620 |  | -					(readq(membar2 + MB2_SHADOW_OFFSET) &  | 
|---|
| 621 |  | -					 PCI_BASE_ADDRESS_MEM_MASK);  | 
|---|
| 622 |  | -			offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -  | 
|---|
| 623 |  | -					(readq(membar2 + MB2_SHADOW_OFFSET + 8) &  | 
|---|
| 624 |  | -					 PCI_BASE_ADDRESS_MEM_MASK);  | 
|---|
| 625 |  | -			pci_iounmap(vmd->dev, membar2);  | 
|---|
| 626 |  | -		}  | 
|---|
 | 599 | +		ret = vmd_get_phys_offsets(vmd, true, &offset[0], &offset[1]);  | 
|---|
 | 600 | +		if (ret)  | 
|---|
 | 601 | +			return ret;  | 
|---|
 | 602 | +	} else if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) {  | 
|---|
 | 603 | +		ret = vmd_get_phys_offsets(vmd, false, &offset[0], &offset[1]);  | 
|---|
 | 604 | +		if (ret)  | 
|---|
 | 605 | +			return ret;  | 
|---|
| 627 | 606 |  	} | 
|---|
| 628 | 607 |   | 
|---|
| 629 | 608 |  	/* | 
|---|
| 630 | 609 |  	 * Certain VMD devices may have a root port configuration option which | 
|---|
| 631 |  | -	 * limits the bus range to between 0-127 or 128-255  | 
|---|
 | 610 | +	 * limits the bus range to between 0-127, 128-255, or 224-255  | 
|---|
| 632 | 611 |  	 */ | 
|---|
| 633 | 612 |  	if (features & VMD_FEAT_HAS_BUS_RESTRICTIONS) { | 
|---|
| 634 |  | -		u32 vmcap, vmconfig;  | 
|---|
| 635 |  | -  | 
|---|
| 636 |  | -		pci_read_config_dword(vmd->dev, PCI_REG_VMCAP, &vmcap);  | 
|---|
| 637 |  | -		pci_read_config_dword(vmd->dev, PCI_REG_VMCONFIG, &vmconfig);  | 
|---|
| 638 |  | -		if (BUS_RESTRICT_CAP(vmcap) &&  | 
|---|
| 639 |  | -		    (BUS_RESTRICT_CFG(vmconfig) == 0x1))  | 
|---|
| 640 |  | -			vmd->busn_start = 128;  | 
|---|
 | 613 | +		ret = vmd_get_bus_number_start(vmd);  | 
|---|
 | 614 | +		if (ret)  | 
|---|
 | 615 | +			return ret;  | 
|---|
| 641 | 616 |  	} | 
|---|
| 642 | 617 |   | 
|---|
| 643 | 618 |  	res = &vmd->dev->resource[VMD_CFGBAR]; | 
|---|
| .. | .. | 
|---|
| 658 | 633 |  	 * 32-bit resources.  __pci_assign_resource() enforces that | 
|---|
| 659 | 634 |  	 * artificial restriction to make sure everything will fit. | 
|---|
| 660 | 635 |  	 * | 
|---|
| 661 |  | -	 * The only way we could use a 64-bit non-prefechable MEMBAR is  | 
|---|
 | 636 | +	 * The only way we could use a 64-bit non-prefetchable MEMBAR is  | 
|---|
| 662 | 637 |  	 * if its address is <4GB so that we can convert it to a 32-bit | 
|---|
| 663 | 638 |  	 * resource.  To be visible to the host OS, all VMD endpoints must | 
|---|
| 664 | 639 |  	 * be initially configured by platform BIOS, which includes setting | 
|---|
| .. | .. | 
|---|
| 691 | 666 |  		.parent = res, | 
|---|
| 692 | 667 |  	}; | 
|---|
| 693 | 668 |   | 
|---|
| 694 |  | -	sd->vmd_domain = true;  | 
|---|
 | 669 | +	sd->vmd_dev = vmd->dev;  | 
|---|
| 695 | 670 |  	sd->domain = vmd_find_free_domain(); | 
|---|
| 696 | 671 |  	if (sd->domain < 0) | 
|---|
| 697 | 672 |  		return sd->domain; | 
|---|
| 698 | 673 |   | 
|---|
| 699 | 674 |  	sd->node = pcibus_to_node(vmd->dev->bus); | 
|---|
| 700 | 675 |   | 
|---|
| 701 |  | -	fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain);  | 
|---|
| 702 |  | -	if (!fn)  | 
|---|
| 703 |  | -		return -ENODEV;  | 
|---|
 | 676 | +	ret = vmd_create_irq_domain(vmd);  | 
|---|
 | 677 | +	if (ret)  | 
|---|
 | 678 | +		return ret;  | 
|---|
| 704 | 679 |   | 
|---|
| 705 |  | -	vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info,  | 
|---|
| 706 |  | -						    x86_vector_domain);  | 
|---|
| 707 |  | -	if (!vmd->irq_domain) {  | 
|---|
| 708 |  | -		irq_domain_free_fwnode(fn);  | 
|---|
| 709 |  | -		return -ENODEV;  | 
|---|
| 710 |  | -	}  | 
|---|
 | 680 | +	/*  | 
|---|
 | 681 | +	 * Override the irq domain bus token so the domain can be distinguished  | 
|---|
 | 682 | +	 * from a regular PCI/MSI domain.  | 
|---|
 | 683 | +	 */  | 
|---|
 | 684 | +	irq_domain_update_bus_token(vmd->irq_domain, DOMAIN_BUS_VMD_MSI);  | 
|---|
| 711 | 685 |   | 
|---|
| 712 | 686 |  	pci_add_resource(&resources, &vmd->resources[0]); | 
|---|
| 713 | 687 |  	pci_add_resource_offset(&resources, &vmd->resources[1], offset[0]); | 
|---|
| 714 | 688 |  	pci_add_resource_offset(&resources, &vmd->resources[2], offset[1]); | 
|---|
| 715 | 689 |   | 
|---|
| 716 | 690 |  	vmd->bus = pci_create_root_bus(&vmd->dev->dev, vmd->busn_start, | 
|---|
| 717 |  | -					&vmd_ops, sd, &resources);  | 
|---|
 | 691 | +				       &vmd_ops, sd, &resources);  | 
|---|
| 718 | 692 |  	if (!vmd->bus) { | 
|---|
| 719 | 693 |  		pci_free_resource_list(&resources); | 
|---|
| 720 |  | -		irq_domain_remove(vmd->irq_domain);  | 
|---|
| 721 |  | -		irq_domain_free_fwnode(fn);  | 
|---|
 | 694 | +		vmd_remove_irq_domain(vmd);  | 
|---|
| 722 | 695 |  		return -ENODEV; | 
|---|
| 723 | 696 |  	} | 
|---|
| 724 | 697 |   | 
|---|
| 725 | 698 |  	vmd_attach_resources(vmd); | 
|---|
| 726 |  | -	vmd_setup_dma_ops(vmd);  | 
|---|
| 727 |  | -	dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);  | 
|---|
| 728 |  | -	pci_rescan_bus(vmd->bus);  | 
|---|
 | 699 | +	if (vmd->irq_domain)  | 
|---|
 | 700 | +		dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);  | 
|---|
 | 701 | +  | 
|---|
 | 702 | +	pci_scan_child_bus(vmd->bus);  | 
|---|
 | 703 | +	pci_assign_unassigned_bus_resources(vmd->bus);  | 
|---|
 | 704 | +  | 
|---|
 | 705 | +	/*  | 
|---|
 | 706 | +	 * VMD root buses are virtual and don't return true on pci_is_pcie()  | 
|---|
 | 707 | +	 * and will fail pcie_bus_configure_settings() early. It can instead be  | 
|---|
 | 708 | +	 * run on each of the real root ports.  | 
|---|
 | 709 | +	 */  | 
|---|
 | 710 | +	list_for_each_entry(child, &vmd->bus->children, node)  | 
|---|
 | 711 | +		pcie_bus_configure_settings(child);  | 
|---|
 | 712 | +  | 
|---|
 | 713 | +	pci_bus_add_devices(vmd->bus);  | 
|---|
| 729 | 714 |   | 
|---|
| 730 | 715 |  	WARN(sysfs_create_link(&vmd->dev->dev.kobj, &vmd->bus->dev.kobj, | 
|---|
| 731 | 716 |  			       "domain"), "Can't create symlink to domain\n"); | 
|---|
| 732 | 717 |  	return 0; | 
|---|
| 733 | 718 |  } | 
|---|
| 734 | 719 |   | 
|---|
| 735 |  | -static irqreturn_t vmd_irq(int irq, void *data)  | 
|---|
| 736 |  | -{  | 
|---|
| 737 |  | -	struct vmd_irq_list *irqs = data;  | 
|---|
| 738 |  | -	struct vmd_irq *vmdirq;  | 
|---|
| 739 |  | -	int idx;  | 
|---|
| 740 |  | -  | 
|---|
| 741 |  | -	idx = srcu_read_lock(&irqs->srcu);  | 
|---|
| 742 |  | -	list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)  | 
|---|
| 743 |  | -		generic_handle_irq(vmdirq->virq);  | 
|---|
| 744 |  | -	srcu_read_unlock(&irqs->srcu, idx);  | 
|---|
| 745 |  | -  | 
|---|
| 746 |  | -	return IRQ_HANDLED;  | 
|---|
| 747 |  | -}  | 
|---|
| 748 |  | -  | 
|---|
| 749 | 720 |  static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) | 
|---|
| 750 | 721 |  { | 
|---|
| 751 | 722 |  	struct vmd_dev *vmd; | 
|---|
| 752 |  | -	int i, err;  | 
|---|
 | 723 | +	int err;  | 
|---|
| 753 | 724 |   | 
|---|
| 754 | 725 |  	if (resource_size(&dev->resource[VMD_CFGBAR]) < (1 << 20)) | 
|---|
| 755 | 726 |  		return -ENOMEM; | 
|---|
| .. | .. | 
|---|
| 772 | 743 |  	    dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32))) | 
|---|
| 773 | 744 |  		return -ENODEV; | 
|---|
| 774 | 745 |   | 
|---|
| 775 |  | -	vmd->msix_count = pci_msix_vec_count(dev);  | 
|---|
| 776 |  | -	if (vmd->msix_count < 0)  | 
|---|
| 777 |  | -		return -ENODEV;  | 
|---|
| 778 |  | -  | 
|---|
| 779 |  | -	vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,  | 
|---|
| 780 |  | -					PCI_IRQ_MSIX);  | 
|---|
| 781 |  | -	if (vmd->msix_count < 0)  | 
|---|
| 782 |  | -		return vmd->msix_count;  | 
|---|
| 783 |  | -  | 
|---|
| 784 |  | -	vmd->irqs = devm_kcalloc(&dev->dev, vmd->msix_count, sizeof(*vmd->irqs),  | 
|---|
| 785 |  | -				 GFP_KERNEL);  | 
|---|
| 786 |  | -	if (!vmd->irqs)  | 
|---|
| 787 |  | -		return -ENOMEM;  | 
|---|
| 788 |  | -  | 
|---|
| 789 |  | -	for (i = 0; i < vmd->msix_count; i++) {  | 
|---|
| 790 |  | -		err = init_srcu_struct(&vmd->irqs[i].srcu);  | 
|---|
| 791 |  | -		if (err)  | 
|---|
| 792 |  | -			return err;  | 
|---|
| 793 |  | -  | 
|---|
| 794 |  | -		INIT_LIST_HEAD(&vmd->irqs[i].irq_list);  | 
|---|
| 795 |  | -		err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i),  | 
|---|
| 796 |  | -				       vmd_irq, IRQF_NO_THREAD,  | 
|---|
| 797 |  | -				       "vmd", &vmd->irqs[i]);  | 
|---|
| 798 |  | -		if (err)  | 
|---|
| 799 |  | -			return err;  | 
|---|
| 800 |  | -	}  | 
|---|
 | 746 | +	err = vmd_alloc_irqs(vmd);  | 
|---|
 | 747 | +	if (err)  | 
|---|
 | 748 | +		return err;  | 
|---|
| 801 | 749 |   | 
|---|
| 802 | 750 |  	spin_lock_init(&vmd->cfg_lock); | 
|---|
| 803 | 751 |  	pci_set_drvdata(dev, vmd); | 
|---|
| .. | .. | 
|---|
| 821 | 769 |  static void vmd_remove(struct pci_dev *dev) | 
|---|
| 822 | 770 |  { | 
|---|
| 823 | 771 |  	struct vmd_dev *vmd = pci_get_drvdata(dev); | 
|---|
| 824 |  | -	struct fwnode_handle *fn = vmd->irq_domain->fwnode;  | 
|---|
| 825 | 772 |   | 
|---|
| 826 | 773 |  	sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); | 
|---|
| 827 | 774 |  	pci_stop_root_bus(vmd->bus); | 
|---|
| 828 | 775 |  	pci_remove_root_bus(vmd->bus); | 
|---|
| 829 | 776 |  	vmd_cleanup_srcu(vmd); | 
|---|
| 830 |  | -	vmd_teardown_dma_ops(vmd);  | 
|---|
| 831 | 777 |  	vmd_detach_resources(vmd); | 
|---|
| 832 |  | -	irq_domain_remove(vmd->irq_domain);  | 
|---|
| 833 |  | -	irq_domain_free_fwnode(fn);  | 
|---|
 | 778 | +	vmd_remove_irq_domain(vmd);  | 
|---|
| 834 | 779 |  } | 
|---|
| 835 | 780 |   | 
|---|
| 836 | 781 |  #ifdef CONFIG_PM_SLEEP | 
|---|
| .. | .. | 
|---|
| 841 | 786 |  	int i; | 
|---|
| 842 | 787 |   | 
|---|
| 843 | 788 |  	for (i = 0; i < vmd->msix_count; i++) | 
|---|
| 844 |  | -                devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);  | 
|---|
 | 789 | +		devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);  | 
|---|
| 845 | 790 |   | 
|---|
| 846 |  | -	pci_save_state(pdev);  | 
|---|
| 847 | 791 |  	return 0; | 
|---|
| 848 | 792 |  } | 
|---|
| 849 | 793 |   | 
|---|
| .. | .. | 
|---|
| 861 | 805 |  			return err; | 
|---|
| 862 | 806 |  	} | 
|---|
| 863 | 807 |   | 
|---|
| 864 |  | -	pci_restore_state(pdev);  | 
|---|
| 865 | 808 |  	return 0; | 
|---|
| 866 | 809 |  } | 
|---|
| 867 | 810 |  #endif | 
|---|
| 868 | 811 |  static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume); | 
|---|
| 869 | 812 |   | 
|---|
| 870 | 813 |  static const struct pci_device_id vmd_ids[] = { | 
|---|
| 871 |  | -	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),},  | 
|---|
 | 814 | +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),  | 
|---|
 | 815 | +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},  | 
|---|
| 872 | 816 |  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0), | 
|---|
| 873 | 817 |  		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW | | 
|---|
| 874 | 818 |  				VMD_FEAT_HAS_BUS_RESTRICTIONS,}, | 
|---|
 | 819 | +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),  | 
|---|
 | 820 | +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |  | 
|---|
 | 821 | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  | 
|---|
 | 822 | +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),  | 
|---|
 | 823 | +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |  | 
|---|
 | 824 | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  | 
|---|
| 875 | 825 |  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B), | 
|---|
| 876 |  | -		.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},  | 
|---|
 | 826 | +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |  | 
|---|
 | 827 | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  | 
|---|
| 877 | 828 |  	{0,} | 
|---|
| 878 | 829 |  }; | 
|---|
| 879 | 830 |  MODULE_DEVICE_TABLE(pci, vmd_ids); | 
|---|