1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2017 Cavium, Inc 3 */ 4 5 #include <rte_eal.h> 6 #include <rte_io.h> 7 #include <rte_pci.h> 8 #include <rte_bus_pci.h> 9 10 #include <octeontx_mbox.h> 11 12 #include "ssovf_evdev.h" 13 #include "timvf_evdev.h" 14 15 #ifndef PCI_VENDOR_ID_CAVIUM 16 #define PCI_VENDOR_ID_CAVIUM (0x177D) 17 #endif 18 19 #define PCI_DEVICE_ID_OCTEONTX_TIM_VF (0xA051) 20 #define TIM_MAX_RINGS (64) 21 22 struct timvf_res { 23 uint8_t in_use; 24 uint16_t domain; 25 uint16_t vfid; 26 void *bar0; 27 void *bar2; 28 void *bar4; 29 }; 30 31 struct timdev { 32 uint8_t total_timvfs; 33 struct timvf_res rings[TIM_MAX_RINGS]; 34 }; 35 36 static struct timdev tdev; 37 38 uint8_t 39 timvf_get_ring(void) 40 { 41 uint16_t global_domain = octeontx_get_global_domain(); 42 int i; 43 44 for (i = 0; i < tdev.total_timvfs; i++) { 45 if (tdev.rings[i].domain != global_domain) 46 continue; 47 if (tdev.rings[i].in_use) 48 continue; 49 50 tdev.rings[i].in_use = true; 51 return tdev.rings[i].vfid; 52 } 53 54 return UINT8_MAX; 55 } 56 57 void 58 timvf_release_ring(uint8_t tim_ring_id) 59 { 60 uint16_t global_domain = octeontx_get_global_domain(); 61 int i; 62 63 for (i = 0; i < tdev.total_timvfs; i++) { 64 if (tdev.rings[i].domain != global_domain) 65 continue; 66 if (tdev.rings[i].vfid == tim_ring_id) 67 tdev.rings[i].in_use = false; 68 } 69 } 70 71 void* 72 timvf_bar(uint8_t vfid, uint8_t bar) 73 { 74 uint16_t global_domain = octeontx_get_global_domain(); 75 struct timvf_res *res = NULL; 76 int i; 77 78 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 79 return NULL; 80 81 for (i = 0; i < tdev.total_timvfs; i++) { 82 if (tdev.rings[i].domain != global_domain) 83 continue; 84 if (tdev.rings[i].vfid == vfid) 85 res = &tdev.rings[i]; 86 87 } 88 89 if (res == NULL) 90 return NULL; 91 92 switch (bar) { 93 case 0: 94 return res->bar0; 95 case 4: 96 return res->bar4; 97 default: 98 return NULL; 99 } 100 } 101 102 static int 103 timvf_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) 104 { 105 uint64_t val; 106 uint16_t vfid; 107 struct timvf_res *res; 108 109 RTE_SET_USED(pci_drv); 110 111 /* For secondary processes, the primary has done all the work */ 112 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 113 return 0; 114 115 if (pci_dev->mem_resource[0].addr == NULL || 116 pci_dev->mem_resource[4].addr == NULL) { 117 timvf_log_err("Empty bars %p %p", 118 pci_dev->mem_resource[0].addr, 119 pci_dev->mem_resource[4].addr); 120 return -ENODEV; 121 } 122 123 val = rte_read64((uint8_t *)pci_dev->mem_resource[0].addr + 124 0x100 /* TIM_VRINGX_BASE */); 125 vfid = (val >> 23) & 0xff; 126 if (vfid >= TIM_MAX_RINGS) { 127 timvf_log_err("Invalid vfid(%d/%d)", vfid, TIM_MAX_RINGS); 128 return -EINVAL; 129 } 130 131 res = &tdev.rings[tdev.total_timvfs]; 132 res->vfid = vfid; 133 res->bar0 = pci_dev->mem_resource[0].addr; 134 res->bar2 = pci_dev->mem_resource[2].addr; 135 res->bar4 = pci_dev->mem_resource[4].addr; 136 res->domain = (val >> 7) & 0xffff; 137 res->in_use = false; 138 tdev.total_timvfs++; 139 rte_wmb(); 140 141 timvf_log_dbg("Domain=%d VFid=%d bar0 %p total_timvfs=%d", res->domain, 142 res->vfid, pci_dev->mem_resource[0].addr, 143 tdev.total_timvfs); 144 return 0; 145 } 146 147 148 static const struct rte_pci_id pci_timvf_map[] = { 149 { 150 RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 151 PCI_DEVICE_ID_OCTEONTX_TIM_VF) 152 }, 153 { 154 .vendor_id = 0, 155 }, 156 }; 157 158 static struct rte_pci_driver pci_timvf = { 159 .id_table = pci_timvf_map, 160 .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_NEED_IOVA_AS_VA, 161 .probe = timvf_probe, 162 .remove = NULL, 163 }; 164 165 RTE_PMD_REGISTER_PCI(octeontx_timvf, pci_timvf); 166