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 { 0x98fa8086, "Intel Lakefield UFS Host Controller", 54 UFSHCI_REF_CLK_19_2MHz, 55 UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE | 56 UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE | 57 UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY }, 58 { 0x54ff8086, "Intel UFS Host Controller", UFSHCI_REF_CLK_19_2MHz }, 59 { 0x00000000, NULL } }; 60 61 static int 62 ufshci_pci_probe(device_t device) 63 { 64 struct ufshci_controller *ctrlr = device_get_softc(device); 65 uint32_t devid = pci_get_devid(device); 66 struct _pcsid *ep = pci_ids; 67 68 while (ep->devid && ep->devid != devid) 69 ++ep; 70 71 if (ep->devid) { 72 ctrlr->quirks = ep->quirks; 73 ctrlr->ref_clk = ep->ref_clk; 74 } 75 76 if (ep->desc) { 77 device_set_desc(device, ep->desc); 78 return (BUS_PROBE_DEFAULT); 79 } 80 81 return (ENXIO); 82 } 83 84 static int 85 ufshci_pci_allocate_bar(struct ufshci_controller *ctrlr) 86 { 87 ctrlr->resource_id = PCIR_BAR(0); 88 89 ctrlr->resource = bus_alloc_resource_any(ctrlr->dev, SYS_RES_MEMORY, 90 &ctrlr->resource_id, RF_ACTIVE); 91 92 if (ctrlr->resource == NULL) { 93 ufshci_printf(ctrlr, "unable to allocate pci resource\n"); 94 return (ENOMEM); 95 } 96 97 ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); 98 ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); 99 ctrlr->regs = (struct ufshci_registers *)ctrlr->bus_handle; 100 101 return (0); 102 } 103 104 static int 105 ufshci_pci_attach(device_t dev) 106 { 107 struct ufshci_controller *ctrlr = device_get_softc(dev); 108 int status; 109 110 ctrlr->dev = dev; 111 status = ufshci_pci_allocate_bar(ctrlr); 112 if (status != 0) 113 goto bad; 114 pci_enable_busmaster(dev); 115 status = ufshci_pci_setup_interrupts(ctrlr); 116 if (status != 0) 117 goto bad; 118 119 return (ufshci_attach(dev)); 120 bad: 121 if (ctrlr->resource != NULL) { 122 bus_release_resource(dev, SYS_RES_MEMORY, ctrlr->resource_id, 123 ctrlr->resource); 124 } 125 126 if (ctrlr->tag) 127 bus_teardown_intr(dev, ctrlr->res, ctrlr->tag); 128 129 if (ctrlr->res) 130 bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(ctrlr->res), 131 ctrlr->res); 132 133 if (ctrlr->msi_count > 0) 134 pci_release_msi(dev); 135 136 return (status); 137 } 138 139 static int 140 ufshci_pci_detach(device_t dev) 141 { 142 struct ufshci_controller *ctrlr = device_get_softc(dev); 143 int error; 144 145 error = ufshci_detach(dev); 146 if (ctrlr->msi_count > 0) 147 pci_release_msi(dev); 148 pci_disable_busmaster(dev); 149 return (error); 150 } 151 152 static int 153 ufshci_pci_setup_shared(struct ufshci_controller *ctrlr, int rid) 154 { 155 int error; 156 157 ctrlr->num_io_queues = 1; 158 ctrlr->rid = rid; 159 ctrlr->res = bus_alloc_resource_any(ctrlr->dev, SYS_RES_IRQ, 160 &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); 161 if (ctrlr->res == NULL) { 162 ufshci_printf(ctrlr, "unable to allocate shared interrupt\n"); 163 return (ENOMEM); 164 } 165 166 error = bus_setup_intr(ctrlr->dev, ctrlr->res, 167 INTR_TYPE_MISC | INTR_MPSAFE, NULL, ufshci_ctrlr_shared_handler, 168 ctrlr, &ctrlr->tag); 169 if (error) { 170 ufshci_printf(ctrlr, "unable to setup shared interrupt\n"); 171 return (error); 172 } 173 174 return (0); 175 } 176 177 static int 178 ufshci_pci_setup_interrupts(struct ufshci_controller *ctrlr) 179 { 180 device_t dev = ctrlr->dev; 181 int force_intx = 0; 182 int num_io_queues, per_cpu_io_queues, min_cpus_per_ioq; 183 int num_vectors_requested; 184 185 TUNABLE_INT_FETCH("hw.ufshci.force_intx", &force_intx); 186 if (force_intx) 187 goto intx; 188 189 if (pci_msix_count(dev) == 0) 190 goto msi; 191 192 /* 193 * Try to allocate one MSI-X per core for I/O queues, plus one 194 * for admin queue, but accept single shared MSI-X if have to. 195 * Fall back to MSI if can't get any MSI-X. 196 */ 197 198 /* 199 * TODO: Need to implement MCQ(Multi Circular Queue) 200 * Example: num_io_queues = mp_ncpus; 201 */ 202 num_io_queues = 1; 203 204 TUNABLE_INT_FETCH("hw.ufshci.num_io_queues", &num_io_queues); 205 if (num_io_queues < 1 || num_io_queues > mp_ncpus) 206 num_io_queues = mp_ncpus; 207 208 per_cpu_io_queues = 1; 209 TUNABLE_INT_FETCH("hw.ufshci.per_cpu_io_queues", &per_cpu_io_queues); 210 if (per_cpu_io_queues == 0) 211 num_io_queues = 1; 212 213 min_cpus_per_ioq = smp_threads_per_core; 214 TUNABLE_INT_FETCH("hw.ufshci.min_cpus_per_ioq", &min_cpus_per_ioq); 215 if (min_cpus_per_ioq > 1) { 216 num_io_queues = min(num_io_queues, 217 max(1, mp_ncpus / min_cpus_per_ioq)); 218 } 219 220 num_io_queues = min(num_io_queues, max(1, pci_msix_count(dev) - 1)); 221 222 again: 223 if (num_io_queues > vm_ndomains) 224 num_io_queues -= num_io_queues % vm_ndomains; 225 num_vectors_requested = min(num_io_queues + 1, pci_msix_count(dev)); 226 ctrlr->msi_count = num_vectors_requested; 227 if (pci_alloc_msix(dev, &ctrlr->msi_count) != 0) { 228 ufshci_printf(ctrlr, "unable to allocate MSI-X\n"); 229 ctrlr->msi_count = 0; 230 goto msi; 231 } 232 if (ctrlr->msi_count == 1) 233 return (ufshci_pci_setup_shared(ctrlr, 1)); 234 if (ctrlr->msi_count != num_vectors_requested) { 235 pci_release_msi(dev); 236 num_io_queues = ctrlr->msi_count - 1; 237 goto again; 238 } 239 240 ctrlr->num_io_queues = num_io_queues; 241 return (0); 242 243 msi: 244 /* 245 * Try to allocate 2 MSIs (admin and I/O queues), but accept single 246 * shared if have to. Fall back to INTx if can't get any MSI. 247 */ 248 ctrlr->msi_count = min(pci_msi_count(dev), 2); 249 if (ctrlr->msi_count > 0) { 250 if (pci_alloc_msi(dev, &ctrlr->msi_count) != 0) { 251 ufshci_printf(ctrlr, "unable to allocate MSI\n"); 252 ctrlr->msi_count = 0; 253 } else if (ctrlr->msi_count == 2) { 254 ctrlr->num_io_queues = 1; 255 return (0); 256 } 257 } 258 259 intx: 260 return (ufshci_pci_setup_shared(ctrlr, ctrlr->msi_count > 0 ? 1 : 0)); 261 } 262