aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/dpaa/bman_portals.c
blob: b0c8200c18801f6bc16bbc2477e6f9178ccdfed1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
 * Copyright (c) 2026 Justin Hibbits
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "opt_platform.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/cpuset.h>
#include <sys/interrupt.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/pcpu.h>
#include <sys/sched.h>

#include <machine/bus.h>
#include <machine/tlb.h>

#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>

#include <powerpc/mpc85xx/mpc85xx.h>

#include "bman.h"
#include "bman_var.h"
#include "portals.h"

#define	BCSP_CFG	0x0100
#define	  CFG_RPM_M	  0x00000003
#define	  CFG_RPM_PI	  0x00000000
#define	  CFG_RPM_PE	  0x00000001
#define	  CFG_RPM_VBM	  0x00000002
#define	BCSP_SCN0	0x0200
#define	BCSP_SCN1	0x0204
#define	BCSP_ISR	0x0e00
#define	BCSP_IER	0x0e04
#define	BCSP_ISDR	0x0e08
#define	  INTR_RCDI	  0x00000004
#define	  INTR_RCRI	  0x00000002
#define	  INTR_BSCN	  0x00000001

#define	BMAN_CE_CR	0x0000
#define	BMAN_CE_RR0	0x0100
#define	BMAN_CE_RR1	0x0140
#define	BMAN_CE_RR(n)	(BMAN_CE_RR0 + 0x40 * (n))
#define	BMAN_CE_RCR	0x1000
#define	BCSP_RCR_PI_CENA	0x3000
#define	BCSP_RCR_CI_CENA	0x3100
#define	BCSP_RCR_PI_CINH	0x000
#define	BCSP_RCR_CI_CINH	0x004

#define	BMAN_MC_VERB_VBIT		0x80
#define	BMAN_MC_VERB_ACQUIRE		0x10
#define	BMAN_MC_VERB_QUERY		0x40
#define	BMAN_RCR_VERB_BPID0		0x20
#define	BMAN_RCR_VERB_BPID_BUF		0x30

struct bman_mc_command {
	uint8_t verb;
	uint8_t cd;
	uint8_t rsvd[62];
};

union bman_mc_result {
	struct {
		uint8_t verb;
		uint8_t cd;
		uint8_t rsvd[62];
	};
	struct {
		uint64_t rsvd_q1[5];
		uint64_t bp_as;
		uint64_t rsvd_q2;
		uint64_t bp_ds;
	};
	struct bman_buffer bufs[8];
};

struct bman_rcr_entry {
	union {
	struct {
		uint8_t verb;
		uint8_t bpid;
		uint8_t rsvd[62];
	};
	struct bman_buffer bufs[8];
	};
};

static void bman_portal_isr(void *arg);

static union bman_mc_result *bman_mc_send(struct bman_portal_softc *p,
    uint8_t verb, uint8_t cd);

DPCPU_DEFINE(struct bman_portal_softc *, bman_affine_portal);

DPAA_RING(bman_rcr, 8, BCSP_RCR_PI_CENA, BCSP_RCR_CI_CENA,
    BCSP_RCR_PI_CINH, BCSP_RCR_CI_CINH);

static uint32_t
bm_ci_read(struct bman_portal_softc *sc, bus_size_t off)
{
	return (bus_read_4(sc->sc_base.sc_mres[1], off));
}

static void
bm_ci_write(struct bman_portal_softc *sc, bus_size_t off, uint32_t val)
{
	bus_write_4(sc->sc_base.sc_mres[1], off, val);
}

int
bman_portal_attach(device_t dev, int cpu)
{
	struct bman_portal_softc *sc = device_get_softc(dev);

	sc->sc_base.sc_cpu = cpu;
	dpaa_portal_alloc_res(dev, cpu);

	bm_ci_write(sc, BCSP_ISDR, 0);
	bm_ci_write(sc, BCSP_IER, INTR_RCRI | INTR_BSCN);
	bus_setup_intr(dev, sc->sc_base.sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
	    NULL, bman_portal_isr, sc, &sc->sc_base.sc_intr_cookie);
	bus_bind_intr(dev, sc->sc_base.sc_ires, cpu);

	/* Select valid-bit mode for rings */
	bus_write_4(sc->sc_base.sc_mres[1], BCSP_CFG, CFG_RPM_VBM);
	/* Disable pool depletion notifications. */
	bm_ci_write(sc, BCSP_SCN0, 0);
	bm_ci_write(sc, BCSP_SCN1, 0);

	DPCPU_ID_SET(cpu, bman_affine_portal, sc);

	sc->sc_rcr.ring =
	    (struct bman_rcr_entry *)(sc->sc_base.sc_ce_va + BMAN_CE_RCR);
	bman_rcr_ring_init(&sc->sc_rcr, &sc->sc_base);
	/* Starting MC polarity is always 1 */
	sc->mc.polarity = BMAN_MC_VERB_VBIT;

	return (0);
}

int
bman_portal_detach(device_t dev)
{
	struct bman_portal_softc *sc;
	int i;

	sc = device_get_softc(dev);


	/* TODO: Unmap TLB regions */
	thread_lock(curthread);
	sched_bind(curthread, sc->sc_base.sc_cpu);
	thread_unlock(curthread);

	if (sc->sc_base.sc_ires != NULL)
		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_base.sc_ires);

	for (i = 0; i < nitems(sc->sc_base.sc_mres); i++) {
		if (sc->sc_base.sc_mres[i] != NULL)
			bus_release_resource(dev, SYS_RES_MEMORY,
			    i, sc->sc_base.sc_mres[i]);
	}
	thread_lock(curthread);
	sched_unbind(curthread);
	thread_unlock(curthread);


	return (0);
}

static uint64_t
bman_query(struct bman_portal_softc *sc, bool depletion)
{
	union bman_mc_result *mc_res;
	uint64_t res;

	critical_enter();
	mc_res = bman_mc_send(sc, BMAN_MC_VERB_QUERY, 0);
	if (mc_res == NULL)
		goto err;

	if (depletion)
		res = mc_res->bp_ds;
	else
		res = mc_res->bp_as;
	critical_exit();

	return (res);

err:
	critical_exit();
	device_printf(sc->sc_base.sc_dev, "Timeout querying depltetion\n");
	return (0);
}

static void
bman_portal_isr(void *arg)
{
	struct bman_portal_softc *sc = arg;
	uint32_t intrs;

	intrs = bm_ci_read(sc, BCSP_ISR);

	/* Release Command Ring interrupt. */
	if (intrs & INTR_RCRI) {
		bman_rcr_update(&sc->sc_rcr, &sc->sc_base);
	}
	/* Buffer Pool State Change Notification. */
	if (intrs & INTR_BSCN) {
		struct bman_pool *pool;
		uint64_t res = bman_query(sc, true);
		if (__predict_true(res != 0)) {
			int idx = flsll(res);
			pool = sc->sc_pools[64 - idx];
			KASSERT(pool != NULL,
			    ("state change on unassociated bpid %d\n", idx));
			pool->dep_cb(pool->arg, true);
		}
	}

	bm_ci_write(sc, BCSP_ISR, intrs);
}

/* RCR */

int
bman_release(struct bman_pool *pool, const struct bman_buffer *bufs,
    uint8_t count)
{
	struct bman_portal_softc *portal;
	struct bman_rcr_entry *rcr;

	if (count > 8)
		return (EINVAL);

	critical_enter();
	portal = DPCPU_GET(bman_affine_portal);
	rcr = bman_rcr_start(&portal->sc_rcr, &portal->sc_base);
	bzero(rcr, sizeof(*rcr));

	/* This should be safe, because bpid must be less than 256. */
	for (int i = 0; i < count; i++)
		rcr->bufs[i] = bufs[i];
	rcr->bufs[0].bpid = pool->bpid;
	bman_rcr_commit(&portal->sc_rcr, BMAN_RCR_VERB_BPID0 | count);
	critical_exit();

	return (0);
}

/* MC commands */
/* Assumes pinned */
static union bman_mc_result *
bman_mc_send(struct bman_portal_softc *p, uint8_t verb, uint8_t cd)
{
	int res_idx;
	struct bman_mc_command *command;
	union bman_mc_result *rr;
	uintptr_t ce_va = p->sc_base.sc_ce_va;

	command = (struct bman_mc_command *)(ce_va + BMAN_CE_CR);
	dpaa_zero_line(command);
	command->cd = cd;
	dpaa_lw_barrier();
	command->verb = verb | p->mc.polarity;
	res_idx = (p->mc.polarity ? 1 : 0);
	p->mc.polarity ^= BMAN_MC_VERB_VBIT;
	dpaa_flush_line(command);

	rr = (union bman_mc_result *)(ce_va + BMAN_CE_RR(res_idx));
	for (;;) {
		if (rr->verb != 0)
			break;
		dpaa_flush_line(rr);
	}
	return (rr);
}

int
bman_acquire(struct bman_pool *pool, struct bman_buffer *bufs, uint8_t count)
{
	union bman_mc_result *rr;

	if (count > 8 || count == 0)
		return (EINVAL);
	critical_enter();
	rr = bman_mc_send(DPCPU_GET(bman_affine_portal),
	    BMAN_MC_VERB_ACQUIRE | count,
	    pool->bpid);
	critical_exit();

	if (rr == NULL)
		return (ETIMEDOUT);
	if ((rr->verb & ~BMAN_MC_VERB_VBIT) == 0)
		return (ENOMEM);

	memcpy(bufs, rr, count * sizeof(*bufs));

	return (0);
}

/*
 * Enable pool state change notifications on this portal.  This requires the
 * pool to already be configured with the callback to handle state changes.
 */
void
bman_portal_enable_scn(struct bman_portal_softc *sc, struct bman_pool *pool)
{
	uint32_t reg, reg_ptr;

	if (pool->bpid >= 32)
		reg_ptr = BCSP_SCN1;
	else
		reg_ptr = BCSP_SCN0;
	reg = bm_ci_read(sc, reg_ptr);
	reg |= (1 << (31 - pool->bpid));
	bm_ci_write(sc, reg_ptr, reg);
	sc->sc_pools[pool->bpid] = pool;
}