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