1*e24a9df7Sskrll /* $NetBSD: apple_nvme.c,v 1.1 2022/05/07 08:20:03 skrll Exp $ */
2*e24a9df7Sskrll /* $OpenBSD: aplns.c,v 1.5 2021/08/29 11:23:29 kettenis Exp $ */
3*e24a9df7Sskrll
4*e24a9df7Sskrll /*-
5*e24a9df7Sskrll * Copyright (c) 2022 The NetBSD Foundation, Inc.
6*e24a9df7Sskrll * All rights reserved.
7*e24a9df7Sskrll *
8*e24a9df7Sskrll * This code is derived from software contributed to The NetBSD Foundation
9*e24a9df7Sskrll * by Nick Hudson
10*e24a9df7Sskrll *
11*e24a9df7Sskrll * Redistribution and use in source and binary forms, with or without
12*e24a9df7Sskrll * modification, are permitted provided that the following conditions
13*e24a9df7Sskrll * are met:
14*e24a9df7Sskrll * 1. Redistributions of source code must retain the above copyright
15*e24a9df7Sskrll * notice, this list of conditions and the following disclaimer.
16*e24a9df7Sskrll * 2. Redistributions in binary form must reproduce the above copyright
17*e24a9df7Sskrll * notice, this list of conditions and the following disclaimer in the
18*e24a9df7Sskrll * documentation and/or other materials provided with the distribution.
19*e24a9df7Sskrll *
20*e24a9df7Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21*e24a9df7Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22*e24a9df7Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23*e24a9df7Sskrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24*e24a9df7Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*e24a9df7Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*e24a9df7Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*e24a9df7Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*e24a9df7Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*e24a9df7Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*e24a9df7Sskrll * POSSIBILITY OF SUCH DAMAGE.
31*e24a9df7Sskrll */
32*e24a9df7Sskrll
33*e24a9df7Sskrll /*
34*e24a9df7Sskrll * Copyright (c) 2014, 2021 David Gwynne <dlg@openbsd.org>
35*e24a9df7Sskrll *
36*e24a9df7Sskrll * Permission to use, copy, modify, and distribute this software for any
37*e24a9df7Sskrll * purpose with or without fee is hereby granted, provided that the above
38*e24a9df7Sskrll * copyright notice and this permission notice appear in all copies.
39*e24a9df7Sskrll *
40*e24a9df7Sskrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
41*e24a9df7Sskrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
42*e24a9df7Sskrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
43*e24a9df7Sskrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
44*e24a9df7Sskrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
45*e24a9df7Sskrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
46*e24a9df7Sskrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
47*e24a9df7Sskrll */
48*e24a9df7Sskrll
49*e24a9df7Sskrll #include <sys/cdefs.h>
50*e24a9df7Sskrll __KERNEL_RCSID(0, "$NetBSD: apple_nvme.c,v 1.1 2022/05/07 08:20:03 skrll Exp $");
51*e24a9df7Sskrll
52*e24a9df7Sskrll #include <sys/param.h>
53*e24a9df7Sskrll
54*e24a9df7Sskrll #include <sys/bus.h>
55*e24a9df7Sskrll #include <sys/device.h>
56*e24a9df7Sskrll #include <sys/kmem.h>
57*e24a9df7Sskrll #include <sys/intr.h>
58*e24a9df7Sskrll
59*e24a9df7Sskrll #include <dev/ic/nvmereg.h>
60*e24a9df7Sskrll #include <dev/ic/nvmevar.h>
61*e24a9df7Sskrll
62*e24a9df7Sskrll #include <dev/fdt/fdtvar.h>
63*e24a9df7Sskrll
64*e24a9df7Sskrll #include <arm/apple/apple_rtkit.h>
65*e24a9df7Sskrll
66*e24a9df7Sskrll int apple_nvme_mpsafe = 1;
67*e24a9df7Sskrll
68*e24a9df7Sskrll #define NVME_IO_Q 1
69*e24a9df7Sskrll
70*e24a9df7Sskrll #define ANS_CPU_CTRL 0x0044
71*e24a9df7Sskrll #define ANS_CPU_CTRL_RUN __BIT(4)
72*e24a9df7Sskrll
73*e24a9df7Sskrll #define ANS_MAX_PEND_CMDS_CTRL 0x01210
74*e24a9df7Sskrll #define ANS_MAX_QUEUE_DEPTH 64
75*e24a9df7Sskrll #define ANS_BOOT_STATUS 0x01300
76*e24a9df7Sskrll #define ANS_BOOT_STATUS_OK 0xde71ce55
77*e24a9df7Sskrll
78*e24a9df7Sskrll #define ANS_MODESEL_REG 0x01304
79*e24a9df7Sskrll #define ANS_UNKNOWN_CTRL 0x24008
80*e24a9df7Sskrll #define ANS_PRP_NULL_CHECK __BIT(11)
81*e24a9df7Sskrll #define ANS_LINEAR_SQ_CTRL 0x24908
82*e24a9df7Sskrll #define ANS_LINEAR_SQ_CTRL_EN __BIT(0)
83*e24a9df7Sskrll #define ANS_LINEAR_ASQ_DB 0x2490c
84*e24a9df7Sskrll #define ANS_LINEAR_IOSQ_DB 0x24910
85*e24a9df7Sskrll
86*e24a9df7Sskrll #define ANS_NVMMU_NUM 0x28100
87*e24a9df7Sskrll #define ANS_NVMMU_BASE_ASQ 0x28108
88*e24a9df7Sskrll #define ANS_NVMMU_BASE_IOSQ 0x28110
89*e24a9df7Sskrll #define ANS_NVMMU_TCB_INVAL 0x28118
90*e24a9df7Sskrll #define ANS_NVMMU_TCB_STAT 0x28120
91*e24a9df7Sskrll
92*e24a9df7Sskrll #define ANS_NVMMU_TCB_SIZE 0x4000
93*e24a9df7Sskrll #define ANS_NVMMU_TCB_PITCH 0x80
94*e24a9df7Sskrll
95*e24a9df7Sskrll struct ans_nvmmu_tcb {
96*e24a9df7Sskrll uint8_t tcb_opcode;
97*e24a9df7Sskrll uint8_t tcb_flags;
98*e24a9df7Sskrll #define ANS_NVMMU_TCB_WRITE __BIT(0)
99*e24a9df7Sskrll #define ANS_NVMMU_TCB_READ __BIT(1)
100*e24a9df7Sskrll uint8_t tcb_cid;
101*e24a9df7Sskrll uint8_t tcb_pad0[1];
102*e24a9df7Sskrll
103*e24a9df7Sskrll uint32_t tcb_prpl_len;
104*e24a9df7Sskrll uint8_t tcb_pad1[16];
105*e24a9df7Sskrll
106*e24a9df7Sskrll uint64_t tcb_prp[2];
107*e24a9df7Sskrll };
108*e24a9df7Sskrll
109*e24a9df7Sskrll void nvme_ans_enable(struct nvme_softc *);
110*e24a9df7Sskrll
111*e24a9df7Sskrll int nvme_ans_q_alloc(struct nvme_softc *, struct nvme_queue *);
112*e24a9df7Sskrll void nvme_ans_q_free(struct nvme_softc *, struct nvme_queue *);
113*e24a9df7Sskrll
114*e24a9df7Sskrll uint32_t
115*e24a9df7Sskrll nvme_ans_sq_enter(struct nvme_softc *, struct nvme_queue *,
116*e24a9df7Sskrll struct nvme_ccb *);
117*e24a9df7Sskrll void nvme_ans_sq_leave(struct nvme_softc *,
118*e24a9df7Sskrll struct nvme_queue *, struct nvme_ccb *);
119*e24a9df7Sskrll
120*e24a9df7Sskrll void nvme_ans_cq_done(struct nvme_softc *,
121*e24a9df7Sskrll struct nvme_queue *, struct nvme_ccb *);
122*e24a9df7Sskrll
123*e24a9df7Sskrll static const struct nvme_ops nvme_ans_ops = {
124*e24a9df7Sskrll .op_enable = nvme_ans_enable,
125*e24a9df7Sskrll
126*e24a9df7Sskrll .op_q_alloc = nvme_ans_q_alloc,
127*e24a9df7Sskrll .op_q_free = nvme_ans_q_free,
128*e24a9df7Sskrll
129*e24a9df7Sskrll .op_sq_enter = nvme_ans_sq_enter,
130*e24a9df7Sskrll .op_sq_leave = nvme_ans_sq_leave,
131*e24a9df7Sskrll .op_sq_enter_locked = nvme_ans_sq_enter,
132*e24a9df7Sskrll .op_sq_leave_locked = nvme_ans_sq_leave,
133*e24a9df7Sskrll
134*e24a9df7Sskrll .op_cq_done = nvme_ans_cq_done,
135*e24a9df7Sskrll };
136*e24a9df7Sskrll
137*e24a9df7Sskrll static const struct device_compatible_entry compat_data[] = {
138*e24a9df7Sskrll { .compat = "apple,nvme-m1" },
139*e24a9df7Sskrll { .compat = "apple,nvme-ans2" },
140*e24a9df7Sskrll DEVICE_COMPAT_EOL
141*e24a9df7Sskrll };
142*e24a9df7Sskrll
143*e24a9df7Sskrll struct apple_nvme_softc {
144*e24a9df7Sskrll struct nvme_softc asc_nvme;
145*e24a9df7Sskrll int asc_phandle;
146*e24a9df7Sskrll
147*e24a9df7Sskrll bus_space_tag_t asc_iot;
148*e24a9df7Sskrll bus_space_handle_t asc_ioh;
149*e24a9df7Sskrll bus_size_t asc_size;
150*e24a9df7Sskrll
151*e24a9df7Sskrll struct rtkit_state *asc_rtkit;
152*e24a9df7Sskrll
153*e24a9df7Sskrll size_t asc_nintrs;
154*e24a9df7Sskrll void *asc_ihs;
155*e24a9df7Sskrll };
156*e24a9df7Sskrll
157*e24a9df7Sskrll void
nvme_ans_enable(struct nvme_softc * sc)158*e24a9df7Sskrll nvme_ans_enable(struct nvme_softc *sc)
159*e24a9df7Sskrll {
160*e24a9df7Sskrll nvme_write4(sc, ANS_NVMMU_NUM,
161*e24a9df7Sskrll (ANS_NVMMU_TCB_SIZE / ANS_NVMMU_TCB_PITCH) - 1);
162*e24a9df7Sskrll nvme_write4(sc, ANS_MODESEL_REG, 0);
163*e24a9df7Sskrll }
164*e24a9df7Sskrll
165*e24a9df7Sskrll
166*e24a9df7Sskrll int
nvme_ans_q_alloc(struct nvme_softc * sc,struct nvme_queue * q)167*e24a9df7Sskrll nvme_ans_q_alloc(struct nvme_softc *sc, struct nvme_queue *q)
168*e24a9df7Sskrll {
169*e24a9df7Sskrll bus_size_t db, base;
170*e24a9df7Sskrll
171*e24a9df7Sskrll KASSERT(q->q_entries <= (ANS_NVMMU_TCB_SIZE / ANS_NVMMU_TCB_PITCH));
172*e24a9df7Sskrll
173*e24a9df7Sskrll q->q_nvmmu_dmamem = nvme_dmamem_alloc(sc, ANS_NVMMU_TCB_SIZE);
174*e24a9df7Sskrll if (q->q_nvmmu_dmamem == NULL)
175*e24a9df7Sskrll return -1;
176*e24a9df7Sskrll
177*e24a9df7Sskrll memset(NVME_DMA_KVA(q->q_nvmmu_dmamem), 0,
178*e24a9df7Sskrll NVME_DMA_LEN(q->q_nvmmu_dmamem));
179*e24a9df7Sskrll
180*e24a9df7Sskrll switch (q->q_id) {
181*e24a9df7Sskrll case NVME_IO_Q:
182*e24a9df7Sskrll db = ANS_LINEAR_IOSQ_DB;
183*e24a9df7Sskrll base = ANS_NVMMU_BASE_IOSQ;
184*e24a9df7Sskrll break;
185*e24a9df7Sskrll case NVME_ADMIN_Q:
186*e24a9df7Sskrll db = ANS_LINEAR_ASQ_DB;
187*e24a9df7Sskrll base = ANS_NVMMU_BASE_ASQ;
188*e24a9df7Sskrll break;
189*e24a9df7Sskrll default:
190*e24a9df7Sskrll panic("unsupported queue id %u", q->q_id);
191*e24a9df7Sskrll /* NOTREACHED */
192*e24a9df7Sskrll }
193*e24a9df7Sskrll
194*e24a9df7Sskrll q->q_sqtdbl = db;
195*e24a9df7Sskrll
196*e24a9df7Sskrll nvme_dmamem_sync(sc, q->q_nvmmu_dmamem, BUS_DMASYNC_PREWRITE);
197*e24a9df7Sskrll nvme_write8(sc, base, NVME_DMA_DVA(q->q_nvmmu_dmamem));
198*e24a9df7Sskrll
199*e24a9df7Sskrll return 0;
200*e24a9df7Sskrll }
201*e24a9df7Sskrll
202*e24a9df7Sskrll void
nvme_ans_q_free(struct nvme_softc * sc,struct nvme_queue * q)203*e24a9df7Sskrll nvme_ans_q_free(struct nvme_softc *sc,
204*e24a9df7Sskrll struct nvme_queue *q)
205*e24a9df7Sskrll {
206*e24a9df7Sskrll nvme_dmamem_sync(sc, q->q_nvmmu_dmamem, BUS_DMASYNC_POSTWRITE);
207*e24a9df7Sskrll nvme_dmamem_free(sc, q->q_nvmmu_dmamem);
208*e24a9df7Sskrll }
209*e24a9df7Sskrll
210*e24a9df7Sskrll uint32_t
nvme_ans_sq_enter(struct nvme_softc * sc,struct nvme_queue * q,struct nvme_ccb * ccb)211*e24a9df7Sskrll nvme_ans_sq_enter(struct nvme_softc *sc,
212*e24a9df7Sskrll struct nvme_queue *q, struct nvme_ccb *ccb)
213*e24a9df7Sskrll {
214*e24a9df7Sskrll return ccb->ccb_id;
215*e24a9df7Sskrll }
216*e24a9df7Sskrll
217*e24a9df7Sskrll static inline struct ans_nvmmu_tcb *
nvme_ans_tcb(struct nvme_queue * q,unsigned int qid)218*e24a9df7Sskrll nvme_ans_tcb(struct nvme_queue *q, unsigned int qid)
219*e24a9df7Sskrll {
220*e24a9df7Sskrll uint8_t *ptr = NVME_DMA_KVA(q->q_nvmmu_dmamem);
221*e24a9df7Sskrll ptr += qid * ANS_NVMMU_TCB_PITCH;
222*e24a9df7Sskrll
223*e24a9df7Sskrll return (struct ans_nvmmu_tcb *)ptr;
224*e24a9df7Sskrll }
225*e24a9df7Sskrll
226*e24a9df7Sskrll void
nvme_ans_sq_leave(struct nvme_softc * sc,struct nvme_queue * q,struct nvme_ccb * ccb)227*e24a9df7Sskrll nvme_ans_sq_leave(struct nvme_softc *sc,
228*e24a9df7Sskrll struct nvme_queue *q, struct nvme_ccb *ccb)
229*e24a9df7Sskrll {
230*e24a9df7Sskrll unsigned int id = ccb->ccb_id;
231*e24a9df7Sskrll struct ans_nvmmu_tcb *tcb = nvme_ans_tcb(q, id);
232*e24a9df7Sskrll struct nvme_sqe_io *sqe = NVME_DMA_KVA(q->q_sq_dmamem);
233*e24a9df7Sskrll sqe += id;
234*e24a9df7Sskrll
235*e24a9df7Sskrll bus_dmamap_sync(sc->sc_dmat, NVME_DMA_MAP(q->q_nvmmu_dmamem),
236*e24a9df7Sskrll ANS_NVMMU_TCB_PITCH * id, sizeof(*tcb), BUS_DMASYNC_POSTWRITE);
237*e24a9df7Sskrll
238*e24a9df7Sskrll memset(tcb, 0, sizeof(*tcb));
239*e24a9df7Sskrll tcb->tcb_opcode = sqe->opcode;
240*e24a9df7Sskrll tcb->tcb_flags = ANS_NVMMU_TCB_WRITE | ANS_NVMMU_TCB_READ;
241*e24a9df7Sskrll tcb->tcb_cid = id;
242*e24a9df7Sskrll tcb->tcb_prpl_len = sqe->nlb;
243*e24a9df7Sskrll tcb->tcb_prp[0] = sqe->entry.prp[0];
244*e24a9df7Sskrll tcb->tcb_prp[1] = sqe->entry.prp[1];
245*e24a9df7Sskrll
246*e24a9df7Sskrll bus_dmamap_sync(sc->sc_dmat, NVME_DMA_MAP(q->q_nvmmu_dmamem),
247*e24a9df7Sskrll ANS_NVMMU_TCB_PITCH * id, sizeof(*tcb), BUS_DMASYNC_PREWRITE);
248*e24a9df7Sskrll nvme_write4(sc, q->q_sqtdbl, id);
249*e24a9df7Sskrll }
250*e24a9df7Sskrll
251*e24a9df7Sskrll void
nvme_ans_cq_done(struct nvme_softc * sc,struct nvme_queue * q,struct nvme_ccb * ccb)252*e24a9df7Sskrll nvme_ans_cq_done(struct nvme_softc *sc,
253*e24a9df7Sskrll struct nvme_queue *q, struct nvme_ccb *ccb)
254*e24a9df7Sskrll {
255*e24a9df7Sskrll unsigned int id = ccb->ccb_id;
256*e24a9df7Sskrll struct ans_nvmmu_tcb *tcb = nvme_ans_tcb(q, id);
257*e24a9df7Sskrll
258*e24a9df7Sskrll bus_dmamap_sync(sc->sc_dmat, NVME_DMA_MAP(q->q_nvmmu_dmamem),
259*e24a9df7Sskrll ANS_NVMMU_TCB_PITCH * id, sizeof(*tcb), BUS_DMASYNC_POSTWRITE);
260*e24a9df7Sskrll memset(tcb, 0, sizeof(*tcb));
261*e24a9df7Sskrll bus_dmamap_sync(sc->sc_dmat, NVME_DMA_MAP(q->q_nvmmu_dmamem),
262*e24a9df7Sskrll ANS_NVMMU_TCB_PITCH * id, sizeof(*tcb), BUS_DMASYNC_PREWRITE);
263*e24a9df7Sskrll
264*e24a9df7Sskrll nvme_write4(sc, ANS_NVMMU_TCB_INVAL, id);
265*e24a9df7Sskrll uint32_t stat = nvme_read4(sc, ANS_NVMMU_TCB_STAT);
266*e24a9df7Sskrll if (stat != 0) {
267*e24a9df7Sskrll printf("%s: nvmmu tcp stat is non-zero: 0x%08x\n",
268*e24a9df7Sskrll device_xname(sc->sc_dev), stat);
269*e24a9df7Sskrll }
270*e24a9df7Sskrll }
271*e24a9df7Sskrll
272*e24a9df7Sskrll
273*e24a9df7Sskrll static int
apple_nvme_intr_establish(struct nvme_softc * sc,uint16_t qid,struct nvme_queue * q)274*e24a9df7Sskrll apple_nvme_intr_establish(struct nvme_softc *sc, uint16_t qid,
275*e24a9df7Sskrll struct nvme_queue *q)
276*e24a9df7Sskrll {
277*e24a9df7Sskrll struct apple_nvme_softc * const asc =
278*e24a9df7Sskrll container_of(sc, struct apple_nvme_softc, asc_nvme);
279*e24a9df7Sskrll const int phandle = asc->asc_phandle;
280*e24a9df7Sskrll char intr_xname[INTRDEVNAMEBUF];
281*e24a9df7Sskrll char intrstr[128];
282*e24a9df7Sskrll const device_t self = sc->sc_dev;
283*e24a9df7Sskrll
284*e24a9df7Sskrll KASSERT(sc->sc_use_mq || qid == NVME_ADMIN_Q);
285*e24a9df7Sskrll KASSERT(sc->sc_ih[qid] == NULL);
286*e24a9df7Sskrll
287*e24a9df7Sskrll if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
288*e24a9df7Sskrll aprint_error(": couldn't decode interrupt\n");
289*e24a9df7Sskrll return 1;
290*e24a9df7Sskrll }
291*e24a9df7Sskrll sc->sc_ih[qid] = fdtbus_intr_establish_xname(phandle, 0, IPL_BIO,
292*e24a9df7Sskrll FDT_INTR_MPSAFE, nvme_intr, sc, device_xname(sc->sc_dev));
293*e24a9df7Sskrll if (sc->sc_ih[qid] == NULL) {
294*e24a9df7Sskrll aprint_error_dev(self, "couldn't establish interrupt on %s\n",
295*e24a9df7Sskrll intrstr);
296*e24a9df7Sskrll return 1;
297*e24a9df7Sskrll }
298*e24a9df7Sskrll
299*e24a9df7Sskrll /* establish also the software interrupt */
300*e24a9df7Sskrll sc->sc_softih[qid] = softint_establish(
301*e24a9df7Sskrll SOFTINT_BIO|(apple_nvme_mpsafe ? SOFTINT_MPSAFE : 0),
302*e24a9df7Sskrll nvme_softintr_intx, q);
303*e24a9df7Sskrll if (sc->sc_softih[qid] == NULL) {
304*e24a9df7Sskrll fdtbus_intr_disestablish(phandle, sc->sc_ih[qid]);
305*e24a9df7Sskrll sc->sc_ih[qid] = NULL;
306*e24a9df7Sskrll
307*e24a9df7Sskrll aprint_error_dev(sc->sc_dev,
308*e24a9df7Sskrll "unable to establish %s soft interrupt\n",
309*e24a9df7Sskrll intr_xname);
310*e24a9df7Sskrll return 1;
311*e24a9df7Sskrll }
312*e24a9df7Sskrll
313*e24a9df7Sskrll if (!sc->sc_use_mq) {
314*e24a9df7Sskrll aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr);
315*e24a9df7Sskrll } else if (qid == NVME_ADMIN_Q) {
316*e24a9df7Sskrll aprint_normal_dev(sc->sc_dev,
317*e24a9df7Sskrll "for admin queue interrupting on %s\n", intrstr);
318*e24a9df7Sskrll } else {
319*e24a9df7Sskrll aprint_normal_dev(sc->sc_dev,
320*e24a9df7Sskrll "for io queue %d interrupting on %s\n", qid, intrstr);
321*e24a9df7Sskrll }
322*e24a9df7Sskrll return 0;
323*e24a9df7Sskrll }
324*e24a9df7Sskrll
325*e24a9df7Sskrll static int
apple_nvme_intr_disestablish(struct nvme_softc * sc,uint16_t qid)326*e24a9df7Sskrll apple_nvme_intr_disestablish(struct nvme_softc *sc, uint16_t qid)
327*e24a9df7Sskrll {
328*e24a9df7Sskrll struct apple_nvme_softc * const asc =
329*e24a9df7Sskrll container_of(sc, struct apple_nvme_softc, asc_nvme);
330*e24a9df7Sskrll
331*e24a9df7Sskrll KASSERT(sc->sc_use_mq || qid == NVME_ADMIN_Q);
332*e24a9df7Sskrll KASSERT(sc->sc_ih[qid] != NULL);
333*e24a9df7Sskrll
334*e24a9df7Sskrll if (sc->sc_softih) {
335*e24a9df7Sskrll softint_disestablish(sc->sc_softih[qid]);
336*e24a9df7Sskrll sc->sc_softih[qid] = NULL;
337*e24a9df7Sskrll }
338*e24a9df7Sskrll
339*e24a9df7Sskrll fdtbus_intr_disestablish(asc->asc_phandle, sc->sc_ih[qid]);
340*e24a9df7Sskrll sc->sc_ih[qid] = NULL;
341*e24a9df7Sskrll
342*e24a9df7Sskrll return 0;
343*e24a9df7Sskrll }
344*e24a9df7Sskrll
345*e24a9df7Sskrll
346*e24a9df7Sskrll static int
apple_nvme_setup_intr(struct fdt_attach_args * const faa,struct apple_nvme_softc * const asc)347*e24a9df7Sskrll apple_nvme_setup_intr(struct fdt_attach_args * const faa,
348*e24a9df7Sskrll struct apple_nvme_softc * const asc)
349*e24a9df7Sskrll {
350*e24a9df7Sskrll struct nvme_softc * const sc = &asc->asc_nvme;
351*e24a9df7Sskrll
352*e24a9df7Sskrll asc->asc_nintrs = 1;
353*e24a9df7Sskrll asc->asc_phandle = faa->faa_phandle;
354*e24a9df7Sskrll
355*e24a9df7Sskrll sc->sc_use_mq = asc->asc_nintrs > 1;
356*e24a9df7Sskrll sc->sc_nq = 1; /* sc_use_mq */
357*e24a9df7Sskrll
358*e24a9df7Sskrll return 0;
359*e24a9df7Sskrll }
360*e24a9df7Sskrll
361*e24a9df7Sskrll
362*e24a9df7Sskrll static int
apple_nvme_match(device_t parent,cfdata_t cf,void * aux)363*e24a9df7Sskrll apple_nvme_match(device_t parent, cfdata_t cf, void *aux)
364*e24a9df7Sskrll {
365*e24a9df7Sskrll struct fdt_attach_args * const faa = aux;
366*e24a9df7Sskrll
367*e24a9df7Sskrll return of_compatible_match(faa->faa_phandle, compat_data);
368*e24a9df7Sskrll }
369*e24a9df7Sskrll
370*e24a9df7Sskrll static void
apple_nvme_attach(device_t parent,device_t self,void * aux)371*e24a9df7Sskrll apple_nvme_attach(device_t parent, device_t self, void *aux)
372*e24a9df7Sskrll {
373*e24a9df7Sskrll struct apple_nvme_softc * const asc = device_private(self);
374*e24a9df7Sskrll struct nvme_softc *sc = &asc->asc_nvme;
375*e24a9df7Sskrll struct fdt_attach_args * const faa = aux;
376*e24a9df7Sskrll const int phandle = faa->faa_phandle;
377*e24a9df7Sskrll bus_addr_t addr, ans_addr;
378*e24a9df7Sskrll bus_size_t size, ans_size;
379*e24a9df7Sskrll uint32_t ctrl, status;
380*e24a9df7Sskrll
381*e24a9df7Sskrll
382*e24a9df7Sskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
383*e24a9df7Sskrll aprint_error(": couldn't get NVME registers\n");
384*e24a9df7Sskrll return;
385*e24a9df7Sskrll }
386*e24a9df7Sskrll
387*e24a9df7Sskrll if (fdtbus_get_reg(phandle, 1, &ans_addr, &ans_size) != 0) {
388*e24a9df7Sskrll aprint_error(": couldn't get ANS registers\n");
389*e24a9df7Sskrll return;
390*e24a9df7Sskrll }
391*e24a9df7Sskrll
392*e24a9df7Sskrll sc->sc_dev = self;
393*e24a9df7Sskrll sc->sc_iot = asc->asc_iot = faa->faa_bst;
394*e24a9df7Sskrll sc->sc_ios = size;
395*e24a9df7Sskrll
396*e24a9df7Sskrll if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
397*e24a9df7Sskrll aprint_error(": couldn't map NVME registers\n");
398*e24a9df7Sskrll return;
399*e24a9df7Sskrll }
400*e24a9df7Sskrll
401*e24a9df7Sskrll if (bus_space_map(asc->asc_iot, ans_addr, ans_size, 0, &asc->asc_ioh) != 0) {
402*e24a9df7Sskrll aprint_error(": couldn't map ANS registers\n");
403*e24a9df7Sskrll goto fail_ansmap;
404*e24a9df7Sskrll }
405*e24a9df7Sskrll
406*e24a9df7Sskrll sc->sc_dmat = faa->faa_dmat;
407*e24a9df7Sskrll sc->sc_ops = &nvme_ans_ops;
408*e24a9df7Sskrll aprint_naive("\n");
409*e24a9df7Sskrll aprint_normal(": Apple NVME\n");
410*e24a9df7Sskrll
411*e24a9df7Sskrll apple_nvme_setup_intr(faa, asc);
412*e24a9df7Sskrll
413*e24a9df7Sskrll sc->sc_intr_establish = apple_nvme_intr_establish;
414*e24a9df7Sskrll sc->sc_intr_disestablish = apple_nvme_intr_disestablish;
415*e24a9df7Sskrll
416*e24a9df7Sskrll sc->sc_ih = kmem_zalloc(sizeof(*sc->sc_ih) * asc->asc_nintrs, KM_SLEEP);
417*e24a9df7Sskrll sc->sc_softih = kmem_zalloc(sizeof(*sc->sc_softih) * asc->asc_nintrs,
418*e24a9df7Sskrll KM_SLEEP);
419*e24a9df7Sskrll
420*e24a9df7Sskrll asc->asc_rtkit = rtkit_init(phandle, NULL);
421*e24a9df7Sskrll if (asc->asc_rtkit == NULL) {
422*e24a9df7Sskrll aprint_error("can't map mailbox channel\n");
423*e24a9df7Sskrll goto fail_rtkit;
424*e24a9df7Sskrll }
425*e24a9df7Sskrll
426*e24a9df7Sskrll ctrl = bus_space_read_4(asc->asc_iot, asc->asc_ioh, ANS_CPU_CTRL);
427*e24a9df7Sskrll bus_space_write_4(asc->asc_iot, asc->asc_ioh, ANS_CPU_CTRL,
428*e24a9df7Sskrll ctrl | ANS_CPU_CTRL_RUN);
429*e24a9df7Sskrll
430*e24a9df7Sskrll status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS);
431*e24a9df7Sskrll if (status != ANS_BOOT_STATUS_OK)
432*e24a9df7Sskrll rtkit_boot(asc->asc_rtkit);
433*e24a9df7Sskrll
434*e24a9df7Sskrll status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_BOOT_STATUS);
435*e24a9df7Sskrll if (status != ANS_BOOT_STATUS_OK) {
436*e24a9df7Sskrll aprint_error("firmware not ready\n");
437*e24a9df7Sskrll goto fail_ansnotready;
438*e24a9df7Sskrll }
439*e24a9df7Sskrll
440*e24a9df7Sskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_LINEAR_SQ_CTRL,
441*e24a9df7Sskrll ANS_LINEAR_SQ_CTRL_EN);
442*e24a9df7Sskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_MAX_PEND_CMDS_CTRL,
443*e24a9df7Sskrll (ANS_MAX_QUEUE_DEPTH << 16) | ANS_MAX_QUEUE_DEPTH);
444*e24a9df7Sskrll
445*e24a9df7Sskrll ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ANS_UNKNOWN_CTRL);
446*e24a9df7Sskrll bus_space_write_4(sc->sc_iot, sc->sc_ioh, ANS_UNKNOWN_CTRL,
447*e24a9df7Sskrll ctrl & ~ANS_PRP_NULL_CHECK);
448*e24a9df7Sskrll
449*e24a9df7Sskrll if (nvme_attach(sc) != 0) {
450*e24a9df7Sskrll /* error printed by nvme_attach() */
451*e24a9df7Sskrll return;
452*e24a9df7Sskrll }
453*e24a9df7Sskrll
454*e24a9df7Sskrll SET(sc->sc_flags, NVME_F_ATTACHED);
455*e24a9df7Sskrll return;
456*e24a9df7Sskrll fail_ansnotready:
457*e24a9df7Sskrll
458*e24a9df7Sskrll fail_rtkit:
459*e24a9df7Sskrll
460*e24a9df7Sskrll fail_ansmap:
461*e24a9df7Sskrll bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
462*e24a9df7Sskrll }
463*e24a9df7Sskrll
464*e24a9df7Sskrll CFATTACH_DECL_NEW(apple_nvme, sizeof(struct apple_nvme_softc),
465*e24a9df7Sskrll apple_nvme_match, apple_nvme_attach, NULL, NULL);
466