arch/powerpc/platforms/pseries/pci.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/pseries/pci.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/pseries/pci.c
Extension
.c
Size
7500 bytes
Lines
294
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pe_map_bar_entry {
	__be64     bar;       /* Input:  Virtual Function BAR */
	__be16     rid;       /* Input:  Virtual Function Router ID */
	__be16     pe_num;    /* Output: Virtual Function PE Number */
	__be32     reserved;  /* Reserved Space */
};

static int pseries_send_map_pe(struct pci_dev *pdev, u16 num_vfs,
			       struct pe_map_bar_entry *vf_pe_array)
{
	struct pci_dn *pdn;
	int rc;
	unsigned long buid, addr;
	int ibm_map_pes = rtas_function_token(RTAS_FN_IBM_OPEN_SRIOV_MAP_PE_NUMBER);

	if (ibm_map_pes == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	pdn = pci_get_pdn(pdev);
	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
	buid = pdn->phb->buid;
	spin_lock(&rtas_data_buf_lock);
	memcpy(rtas_data_buf, vf_pe_array,
	       RTAS_DATA_BUF_SIZE);
	rc = rtas_call(ibm_map_pes, 5, 1, NULL, addr,
		       BUID_HI(buid), BUID_LO(buid),
		       rtas_data_buf,
		       num_vfs * sizeof(struct pe_map_bar_entry));
	memcpy(vf_pe_array, rtas_data_buf, RTAS_DATA_BUF_SIZE);
	spin_unlock(&rtas_data_buf_lock);

	if (rc)
		dev_err(&pdev->dev,
			"%s: Failed to associate pes PE#%lx, rc=%x\n",
			__func__,  addr, rc);

	return rc;
}

static void pseries_set_pe_num(struct pci_dev *pdev, u16 vf_index, __be16 pe_num)
{
	struct pci_dn *pdn;

	pdn = pci_get_pdn(pdev);
	pdn->pe_num_map[vf_index] = be16_to_cpu(pe_num);
	dev_dbg(&pdev->dev, "VF %04x:%02x:%02x.%x associated with PE#%x\n",
		pci_domain_nr(pdev->bus),
		pdev->bus->number,
		PCI_SLOT(pci_iov_virtfn_devfn(pdev, vf_index)),
		PCI_FUNC(pci_iov_virtfn_devfn(pdev, vf_index)),
		pdn->pe_num_map[vf_index]);
}

static int pseries_associate_pes(struct pci_dev *pdev, u16 num_vfs)
{
	struct pci_dn *pdn;
	int i, rc, vf_index;
	struct pe_map_bar_entry *vf_pe_array;
	struct resource *res;
	u64 size;

	vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!vf_pe_array)
		return -ENOMEM;

	pdn = pci_get_pdn(pdev);
	/* create firmware structure to associate pes */
	for (vf_index = 0; vf_index < num_vfs; vf_index++) {
		pdn->pe_num_map[vf_index] = IODA_INVALID_PE;
		for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
			res = &pdev->resource[i + PCI_IOV_RESOURCES];
			if (!res->parent)
				continue;
			size = pcibios_iov_resource_alignment(pdev, i +
					PCI_IOV_RESOURCES);
			vf_pe_array[vf_index].bar =
				cpu_to_be64(res->start + size * vf_index);
			vf_pe_array[vf_index].rid =
				cpu_to_be16((pci_iov_virtfn_bus(pdev, vf_index)
					    << 8) | pci_iov_virtfn_devfn(pdev,
					    vf_index));
			vf_pe_array[vf_index].pe_num =
				cpu_to_be16(IODA_INVALID_PE);
		}
	}

	rc = pseries_send_map_pe(pdev, num_vfs, vf_pe_array);
	/* Only zero is success */
	if (!rc)
		for (vf_index = 0; vf_index < num_vfs; vf_index++)

Annotation

Implementation Notes