1 /*
2  * Copyright (C) 2021-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <errno.h>
9 #include <stddef.h>
10 #include <sys/queue.h>
11 #include <stdlib.h>
12 
13 #include "pcireg.h"
14 #include "pciaccess.h"
15 #include "pci_core.h"
16 #include "pci_util.h"
17 #include "log.h"
18 
19 
20 /* find position of specified pci capability register*/
pci_find_cap(struct pci_device * pdev,const int cap_id)21 int pci_find_cap(struct pci_device *pdev, const int cap_id)
22 {
23 	uint8_t cap_pos, cap_data;
24 	uint16_t status = 0;
25 
26 	pci_device_cfg_read_u16(pdev, &status, PCIR_STATUS);
27 	if (status & PCIM_STATUS_CAPPRESENT) {
28 		pci_device_cfg_read_u8(pdev, &cap_pos, PCIR_CAP_PTR);
29 
30 		while (cap_pos != 0 && cap_pos != 0xff) {
31 			pci_device_cfg_read_u8(pdev, &cap_data,
32 					cap_pos + PCICAP_ID);
33 
34 			if (cap_data == cap_id)
35 				return cap_pos;
36 
37 			pci_device_cfg_read_u8(pdev, &cap_pos,
38 					cap_pos + PCICAP_NEXTPTR);
39 		}
40 	}
41 
42 	return 0;
43 }
44 
45 /* find extend capability register position from cap_id */
pci_find_ext_cap(struct pci_device * pdev,int cap_id)46 int pci_find_ext_cap(struct pci_device *pdev, int cap_id)
47 {
48 	int offset = 0;
49 	uint32_t data = 0;
50 
51 	offset = PCIR_EXTCAP;
52 
53 	do {
54 		/* PCI Express Extended Capability must have 4 bytes header */
55 		pci_device_cfg_read_u32(pdev, &data, offset);
56 
57 		if (PCI_EXTCAP_ID(data) == cap_id)
58 			break;
59 
60 		offset = PCI_EXTCAP_NEXTPTR(data);
61 	} while (offset != 0);
62 
63 	return offset;
64 }
65 
66 /* find pci-e device type */
pci_get_pcie_type(struct pci_device * dev)67 int pci_get_pcie_type(struct pci_device *dev)
68 {
69 	uint8_t data = 0;
70 	int pcie_type;
71 	int pos = 0;
72 
73 	if (dev == NULL)
74 		return -EINVAL;
75 
76 	pos = pci_find_cap(dev, PCIY_EXPRESS);
77 	if (!pos)
78 		return -EINVAL;
79 
80 	pci_device_cfg_read_u8(dev, &data, pos + PCIER_FLAGS);
81 	pcie_type = data & PCIEM_FLAGS_TYPE;
82 
83 	return pcie_type;
84 }
85 
86 /* check whether pdev is a pci root port */
is_root_port(struct pci_device * pdev)87 bool is_root_port(struct pci_device *pdev)
88 {
89 	int pcie_type;
90 
91 	pcie_type = pci_get_pcie_type(pdev);
92 
93 	return (pcie_type == PCIEM_TYPE_ROOT_PORT);
94 }
95 
96 /* check whether pdev is multi-function device */
is_mfdev(struct pci_device * pdev)97 bool is_mfdev(struct pci_device *pdev)
98 {
99 	uint8_t hdr_type;
100 
101 	pci_device_cfg_read_u8(pdev, &hdr_type, PCIR_HDRTYPE);
102 
103 	return ((hdr_type & PCIM_MFDEV) == PCIM_MFDEV);
104 }
105