1 /*- 2 * Copyright (c) 2025, Samsung Electronics Co., Ltd. 3 * Written by Jaeyoon Choi 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <sys/param.h> 9 #include <sys/systm.h> 10 #include <sys/buf.h> 11 #include <sys/bus.h> 12 #include <sys/conf.h> 13 #include <sys/proc.h> 14 #include <sys/smp.h> 15 16 #include <vm/vm.h> 17 18 #include <dev/pci/pcireg.h> 19 #include <dev/pci/pcivar.h> 20 21 #include "ufshci_private.h" 22 23 static int ufshci_pci_probe(device_t); 24 static int ufshci_pci_attach(device_t); 25 static int ufshci_pci_detach(device_t); 26 27 static int ufshci_pci_setup_interrupts(struct ufshci_controller *ctrlr); 28 29 static device_method_t ufshci_pci_methods[] = { 30 /* Device interface */ 31 DEVMETHOD(device_probe, ufshci_pci_probe), 32 DEVMETHOD(device_attach, ufshci_pci_attach), 33 DEVMETHOD(device_detach, ufshci_pci_detach), 34 /* TODO: Implement Suspend, Resume */ 35 { 0, 0 } 36 }; 37 38 static driver_t ufshci_pci_driver = { 39 "ufshci", 40 ufshci_pci_methods, 41 sizeof(struct ufshci_controller), 42 }; 43 44 DRIVER_MODULE(ufshci, pci, ufshci_pci_driver, 0, 0); 45 46 static struct _pcsid { 47 uint32_t devid; 48 const char *desc; 49 uint32_t ref_clk; 50 uint32_t quirks; 51 } pci_ids[] = { { 0x131b36, "QEMU UFS Host Controller", UFSHCI_REF_CLK_19_2MHz, 52 UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE | 53 UFSHCI_QUIRK_NOT_SUPPORT_ABORT_TASK }, 54 { 0x98fa8086, "Intel Lakefield UFS Host Controller", 55 UFSHCI_REF_CLK_19_2MHz, 56 UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE | 57 UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE | 58 UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY }, 59 { 0x54ff8086, "Intel UFS Host Controller", UFSHCI_REF_CLK_19_2MHz }, 60 { 0x00000000, NULL } }; 61 62 static int 63 ufshci_pci_probe(device_t device) 64 { 65 struct ufshci_controller *ctrlr = device_get_softc(device); 66 uint32_t devid = pci_get_devid(device); 67 struct _pcsid *ep = pci_ids; 68 69 while (ep->devid && ep->devid != devid) 70 ++ep; 71 72 if (ep->devid) { 73 ctrlr->quirks = ep->quirks; 74 ctrlr->ref_clk = ep->ref_clk; 75 } 76 77 if (ep->desc) { 78 device_set_desc(device, ep->desc); 79 return (BUS_PROBE_DEFAULT); 80 } 81 82 return (ENXIO); 83 } 84 85 static int 86 ufshci_pci_allocate_bar(struct ufshci_controller *ctrlr) 87 { 88 ctrlr->resource_id = PCIR_BAR(0); 89 90 ctrlr->resource = bus_alloc_resource_any(ctrlr->dev, SYS_RES_MEMORY, 91 &ctrlr->resource_id, RF_ACTIVE); 92 93 if (ctrlr->resource == NULL) { 94 ufshci_printf(ctrlr, "unable to allocate pci resource\n"); 95 return (ENOMEM); 96 } 97 98 ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); 99 ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); 100 ctrlr->regs = (struct ufshci_registers *)ctrlr->bus_handle; 101 102 return (0); 103 } 104 105 static int 106 ufshci_pci_attach(device_t dev) 107 { 108 struct ufshci_controller *ctrlr = device_get_softc(dev); 109 int status; 110 111 ctrlr->dev = dev; 112 status = ufshci_pci_allocate_bar(ctrlr); 113 if (status != 0) 114 goto bad; 115 pci_enable_busmaster(dev); 116 status = ufshci_pci_setup_interrupts(ctrlr); 117 if (status != 0) 118 goto bad; 119 120 return (ufshci_attach(dev)); 121 bad: 122 if (ctrlr->resource != NULL) { 123 bus_release_resource(dev, SYS_RES_MEMORY, ctrlr->resource_id, 124 ctrlr->resource); 125 } 126 127 if (ctrlr->tag) 128 bus_teardown_intr(dev, ctrlr->res, ctrlr->tag); 129 130 if (ctrlr->res) 131 bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(ctrlr->res), 132 ctrlr->res); 133 134 if (ctrlr->msi_count > 0) 135 pci_release_msi(dev); 136 137 return (status); 138 } 139 140 static int 141 ufshci_pci_detach(device_t dev) 142 { 143 struct ufshci_controller *ctrlr = device_get_softc(dev); 144 int error; 145 146 error = ufshci_detach(dev); 147 if (ctrlr->msi_count > 0) 148 pci_release_msi(dev); 149 pci_disable_busmaster(dev); 150 return (error); 151 } 152 153 static int 154 ufshci_pci_setup_shared(struct ufshci_controller *ctrlr, int rid) 155 { 156 int error; 157 158 ctrlr->num_io_queues = 1; 159 ctrlr->rid = rid; 160 ctrlr->res = bus_alloc_resource_any(ctrlr->dev, SYS_RES_IRQ, 161 &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); 162 if (ctrlr->res == NULL) { 163 ufshci_printf(ctrlr, "unable to allocate shared interrupt\n"); 164 return (ENOMEM); 165 } 166 167 error = bus_setup_intr(ctrlr->dev, ctrlr->res, 168 INTR_TYPE_MISC | INTR_MPSAFE, NULL, ufshci_ctrlr_shared_handler, 169 ctrlr, &ctrlr->tag); 170 if (error) { 171 ufshci_printf(ctrlr, "unable to setup shared interrupt\n"); 172 return (error); 173 } 174 175 return (0); 176 } 177 178 static int 179 ufshci_pci_setup_interrupts(struct ufshci_controller *ctrlr) 180 { 181 device_t dev = ctrlr->dev; 182 int force_intx = 0; 183 int num_io_queues, per_cpu_io_queues, min_cpus_per_ioq; 184 int num_vectors_requested; 185 186 TUNABLE_INT_FETCH("hw.ufshci.force_intx", &force_intx); 187 if (force_intx) 188 goto intx; 189 190 if (pci_msix_count(dev) == 0) 191 goto msi; 192 193 /* 194 * Try to allocate one MSI-X per core for I/O queues, plus one 195 * for admin queue, but accept single shared MSI-X if have to. 196 * Fall back to MSI if can't get any MSI-X. 197 */ 198 199 /* 200 * TODO: Need to implement MCQ(Multi Circular Queue) 201 * Example: num_io_queues = mp_ncpus; 202 */ 203 num_io_queues = 1; 204 205 TUNABLE_INT_FETCH("hw.ufshci.num_io_queues", &num_io_queues); 206 if (num_io_queues < 1 || num_io_queues > mp_ncpus) 207 num_io_queues = mp_ncpus; 208 209 per_cpu_io_queues = 1; 210 TUNABLE_INT_FETCH("hw.ufshci.per_cpu_io_queues", &per_cpu_io_queues); 211 if (per_cpu_io_queues == 0) 212 num_io_queues = 1; 213 214 min_cpus_per_ioq = smp_threads_per_core; 215 TUNABLE_INT_FETCH("hw.ufshci.min_cpus_per_ioq", &min_cpus_per_ioq); 216 if (min_cpus_per_ioq > 1) { 217 num_io_queues = min(num_io_queues, 218 max(1, mp_ncpus / min_cpus_per_ioq)); 219 } 220 221 num_io_queues = min(num_io_queues, max(1, pci_msix_count(dev) - 1)); 222 223 again: 224 if (num_io_queues > vm_ndomains) 225 num_io_queues -= num_io_queues % vm_ndomains; 226 num_vectors_requested = min(num_io_queues + 1, pci_msix_count(dev)); 227 ctrlr->msi_count = num_vectors_requested; 228 if (pci_alloc_msix(dev, &ctrlr->msi_count) != 0) { 229 ufshci_printf(ctrlr, "unable to allocate MSI-X\n"); 230 ctrlr->msi_count = 0; 231 goto msi; 232 } 233 if (ctrlr->msi_count == 1) 234 return (ufshci_pci_setup_shared(ctrlr, 1)); 235 if (ctrlr->msi_count != num_vectors_requested) { 236 pci_release_msi(dev); 237 num_io_queues = ctrlr->msi_count - 1; 238 goto again; 239 } 240 241 ctrlr->num_io_queues = num_io_queues; 242 return (0); 243 244 msi: 245 /* 246 * Try to allocate 2 MSIs (admin and I/O queues), but accept single 247 * shared if have to. Fall back to INTx if can't get any MSI. 248 */ 249 ctrlr->msi_count = min(pci_msi_count(dev), 2); 250 if (ctrlr->msi_count > 0) { 251 if (pci_alloc_msi(dev, &ctrlr->msi_count) != 0) { 252 ufshci_printf(ctrlr, "unable to allocate MSI\n"); 253 ctrlr->msi_count = 0; 254 } else if (ctrlr->msi_count == 2) { 255 ctrlr->num_io_queues = 1; 256 return (0); 257 } 258 } 259 260 intx: 261 return (ufshci_pci_setup_shared(ctrlr, ctrlr->msi_count > 0 ? 1 : 0)); 262 } 263