Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: octeon_powvar.h,v 1.7 2020/06/23 05:15:33 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007 Internet Initiative Japan, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #ifndef _OCTEON_POWVAR_H_
     30 #define _OCTEON_POWVAR_H_
     31 
     32 #include <sys/cpu.h>
     33 
     34 #include <mips/cavium/octeonreg.h>
     35 
     36 #define POW_TAG_TYPE_ORDERED	0
     37 #define POW_TAG_TYPE_ATOMIC	1
     38 #define POW_TAG_TYPE_NULL	2
     39 #define POW_TAG_TYPE_NULL_NULL	3
     40 
     41 #define POW_TAG_OP_SWTAG		0
     42 #define POW_TAG_OP_SWTAG_FULL		1
     43 #define POW_TAG_OP_SWTAG_DESCHED	2
     44 #define POW_TAG_OP_DESCHED		3
     45 #define POW_TAG_OP_ADDWQ		4
     46 #define POW_TAG_OP_UPD_WQP_GRP		5
     47 #define POW_TAG_OP_CLR_NSCHED		7
     48 #define POW_TAG_OP_NOP			15
     49 
     50 #define POW_WAIT	1
     51 #define POW_NO_WAIT	0
     52 
     53 #define	POW_WORKQ_IRQ(group)		(group)
     54 
     55 /* XXX */
     56 struct octpow_softc {
     57 	device_t		sc_dev;
     58 	bus_space_tag_t		sc_regt;
     59 	bus_space_handle_t	sc_regh;
     60 	int			sc_port;
     61 	int			sc_int_pc_base;
     62 };
     63 
     64 /* XXX */
     65 struct octpow_attach_args {
     66 	int			aa_port;
     67 	bus_space_tag_t		aa_regt;
     68 };
     69 
     70 void		octpow_config(struct octpow_softc *, int);
     71 void		octpow_error_int_enable(void *, int);
     72 uint64_t	octpow_error_int_summary(void *);
     73 int		octpow_ring_reduce(void *);
     74 int		octpow_ring_grow(void *);
     75 int		octpow_ring_size(void);
     76 int		octpow_ring_intr(void);
     77 
     78 #define	_POW_RD8(sc, off) \
     79 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
     80 #define	_POW_WR8(sc, off, v) \
     81 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
     82 #define	_POW_GROUP_RD8(sc, pi, off) \
     83 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
     84 	    (off) + sizeof(uint64_t) * (pi)->pi_group)
     85 #define	_POW_GROUP_WR8(sc, pi, off, v) \
     86 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
     87 	    (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
     88 
     89 extern struct octpow_softc	octpow_softc;
     90 
     91 /* -------------------------------------------------------------------------- */
     92 
     93 /* Load Operations */
     94 
     95 /* GET_WORK Loads */
     96 
     97 static __inline uint64_t
     98 octpow_ops_get_work_load(
     99 	int wait)			/* 0-1 */
    100 {
    101 	uint64_t ptr =
    102 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_GET_WORK) |
    103 	    (wait ? POW_GET_WORK_LOAD_WAIT : 0);
    104 
    105 	return octeon_xkphys_read_8(ptr);
    106 }
    107 
    108 /* IOBDMA Operations */
    109 
    110 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
    111 
    112 /* The ``scraddr'' part is index in 8 byte words, not address. */
    113 
    114 /* GET_WORK IOBDMAs */
    115 
    116 static __inline void
    117 octpow_ops_get_work_iobdma(
    118 	int scraddr,			/* 0-2047 */
    119 	int wait)			/* 0-1 */
    120 {
    121  	/* ``scraddr'' part is index in 64-bit words, not address */
    122 	const int scrindex = scraddr / sizeof(uint64_t);
    123 
    124 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
    125 	    POW_IOBDMA_SUBDID_GET_WORK, scrindex, POW_IOBDMA_LEN,
    126 	    wait ? POW_IOBDMA_GET_WORK_WAIT : 0);
    127 
    128         octeon_iobdma_write_8(value);
    129 }
    130 
    131 /* NULL_RD IOBDMAs */
    132 
    133 static __inline void
    134 octpow_ops_null_rd_iobdma(
    135 	int scraddr)			/* 0-2047 */
    136 {
    137  	/* ``scraddr'' part is index in 64-bit words, not address */
    138 	const int scrindex = scraddr / sizeof(uint64_t);
    139 
    140 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
    141 	    POW_IOBDMA_SUBDID_NULL_RD, scrindex, POW_IOBDMA_LEN, 0);
    142 
    143         octeon_iobdma_write_8(value);
    144 }
    145 
    146 /* Store Operations */
    147 
    148 static __inline void
    149 octpow_store(
    150 	int subdid,			/* 0, 1, 3 */
    151 	uint64_t addr,			/* 0-0x0000.000f.ffff.ffff */
    152 	int no_sched,			/* 0, 1 */
    153 	int index,			/* 0-8191 */
    154 	int op,				/* 0-15 */
    155 	int qos,			/* 0-7 */
    156 	int grp,			/* 0-7 */
    157 	int type,			/* 0-7 */
    158 	uint32_t tag)			/* 0-0xffff.ffff */
    159 {
    160 	/* Physical Address to Store to POW */
    161 	uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, subdid) |
    162 	    __SHIFTIN(addr, POW_PHY_ADDR_STORE_ADDR);
    163 
    164 	/* Store Data on Store to POW */
    165 	uint64_t args =
    166 	    __SHIFTIN(no_sched, POW_STORE_DATA_NO_SCHED) |
    167 	    __SHIFTIN(index, POW_STORE_DATA_INDEX) |
    168 	    __SHIFTIN(op, POW_STORE_DATA_OP) |
    169 	    __SHIFTIN(qos, POW_STORE_DATA_QOS) |
    170 	    __SHIFTIN(grp, POW_STORE_DATA_GRP) |
    171 	    __SHIFTIN(type, POW_STORE_DATA_TYPE) |
    172 	    __SHIFTIN(tag, POW_STORE_DATA_TAG);
    173 
    174 	octeon_xkphys_write_8(ptr, args);
    175 }
    176 
    177 /* SWTAG */
    178 
    179 static __inline void
    180 octpow_ops_swtag(int type, uint32_t tag)
    181 {
    182 
    183 	octpow_store(
    184 		POW_STORE_SUBDID_OTHER,
    185 		0, 			/* addr (not used for SWTAG) */
    186 		0,			/* no_sched (not used for SWTAG) */
    187 		0,			/* index (not used for SWTAG) */
    188 		POW_TAG_OP_SWTAG,	/* op == SWTAG */
    189 		0,			/* qos (not used for SWTAG) */
    190 		0,			/* grp (not used for SWTAG) */
    191 		type,
    192 		tag);
    193 	/* switch to NULL completes immediately */
    194 }
    195 
    196 /* SWTAG_FULL */
    197 
    198 static __inline void
    199 octpow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
    200 {
    201 
    202 	octpow_store(
    203 		POW_STORE_SUBDID_SWTAG_FULL,
    204 		addr,
    205 		0,			/* no_sched (not used for SWTAG_FULL) */
    206 		0,			/* index (not used for SWTAG_FULL) */
    207 		POW_TAG_OP_SWTAG_FULL,	/* op == SWTAG_FULL */
    208 		0,			/* qos (not used for SWTAG_FULL) */
    209 		grp,
    210 		type,
    211 		tag);
    212 }
    213 
    214 /* SWTAG_DESCHED */
    215 
    216 static __inline void
    217 octpow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
    218 {
    219 
    220 	octpow_store(
    221 		POW_STORE_SUBDID_DESCHED,
    222 		0,			/* addr (not used for SWTAG_DESCHED) */
    223 		no_sched,
    224 		0,			/* index (not used for SWTAG_DESCHED) */
    225 		POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
    226 		0,			/* qos (not used for SWTAG_DESCHED) */
    227 		grp,
    228 		type,
    229 		tag);
    230 }
    231 
    232 /* DESCHED */
    233 
    234 static __inline void
    235 octpow_ops_desched(int no_sched)
    236 {
    237 
    238 	octpow_store(
    239 		POW_STORE_SUBDID_DESCHED,
    240 		0,			/* addr (not used for DESCHED) */
    241 		no_sched,
    242 		0,			/* index (not used for DESCHED) */
    243 		POW_TAG_OP_DESCHED,	/* op == DESCHED */
    244 		0,			/* qos (not used for DESCHED) */
    245 		0,			/* grp (not used for DESCHED) */
    246 		0,			/* type (not used for DESCHED) */
    247 		0);			/* tag (not used for DESCHED) */
    248 }
    249 
    250 /* ADDWQ */
    251 
    252 static __inline void
    253 octpow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
    254 {
    255 
    256 	octpow_store(
    257 		POW_STORE_SUBDID_OTHER,
    258 		addr,
    259 		0,			/* no_sched (not used for ADDWQ) */
    260 		0,			/* index (not used for ADDWQ) */
    261 		POW_TAG_OP_ADDWQ,	/* op == ADDWQ */
    262 		qos,
    263 		grp,
    264 		type,
    265 		tag);
    266 }
    267 
    268 /* UPD_WQP_GRP */
    269 
    270 static __inline void
    271 octpow_ops_upd_wqp_grp(paddr_t addr, int grp)
    272 {
    273 
    274 	octpow_store(
    275 		POW_STORE_SUBDID_OTHER,
    276 		addr,
    277 		0,			/* no_sched (not used for UPD_WQP_GRP) */
    278 		0,			/* index (not used for UPD_WQP_GRP) */
    279 		POW_TAG_OP_UPD_WQP_GRP,	/* op == UPD_WQP_GRP */
    280 		0,			/* qos (not used for UPD_WQP_GRP) */
    281 		grp,
    282 		0,			/* type (not used for UPD_WQP_GRP) */
    283 		0);			/* tag (not used for UPD_WQP_GRP) */
    284 }
    285 
    286 /* CLR_NSCHED */
    287 
    288 static __inline void
    289 octpow_ops_clr_nsched(paddr_t addr, int index)
    290 {
    291 
    292 	octpow_store(
    293 		POW_STORE_SUBDID_OTHER,
    294 		addr,
    295 		0,			/* no_sched (not used for CLR_NSCHED) */
    296 		index,
    297 		POW_TAG_OP_CLR_NSCHED,	/* op == CLR_NSCHED */
    298 		0,			/* qos (not used for CLR_NSCHED) */
    299 		0,			/* grp (not used for CLR_NSCHED) */
    300 		0,			/* type (not used for CLR_NSCHED) */
    301 		0);			/* tag (not used for CLR_NSCHED) */
    302 }
    303 
    304 /* NOP */
    305 
    306 static __inline void
    307 octpow_ops_nop(void)
    308 {
    309 
    310 	octpow_store(
    311 		POW_STORE_SUBDID_OTHER,
    312 		0,			/* addr (not used for NOP) */
    313 		0,			/* no_sched (not used for NOP) */
    314 		0,			/* index (not used for NOP) */
    315 		POW_TAG_OP_NOP,		/* op == NOP */
    316 		0,			/* qos (not used for NOP) */
    317 		0,			/* grp (not used for NOP) */
    318 		0,			/* type (not used for NOP) */
    319 		0);			/* tag (not used for NOP) */
    320 }
    321 
    322 /*
    323  * Check if there is a pending POW tag switch.
    324  */
    325 static __inline int
    326 octpow_tag_sw_pending(void)
    327 {
    328 	int result;
    329 
    330 	/*
    331 	 * "RDHWR rt, $30" returns:
    332 	 *	0 => pending bit is set
    333 	 *	1 => pending bit is clear
    334 	 */
    335 
    336 	__asm volatile (
    337 		"	.set	push\n"
    338 		"	.set	noreorder\n"
    339 		"	.set	arch=mips64r2\n"
    340 		"	rdhwr	%0, $30\n"
    341 		"	.set	pop\n"
    342 		: "=r" (result));
    343 	return result == 0;
    344 }
    345 
    346 /*
    347  * Wait until there is no pending POW tag switch.
    348  */
    349 static inline void
    350 octpow_tag_sw_wait(void)
    351 {
    352 	while (octpow_tag_sw_pending())
    353 		continue;
    354 }
    355 
    356 /* -------------------------------------------------------------------------- */
    357 
    358 /*
    359  * global functions
    360  */
    361 static __inline void
    362 octpow_work_request_async(uint64_t scraddr, uint64_t wait)
    363 {
    364 
    365         octpow_ops_get_work_iobdma(scraddr, wait);
    366 }
    367 
    368 static __inline uint64_t *
    369 octpow_work_response_async(uint64_t scraddr)
    370 {
    371 	uint64_t result;
    372 
    373 	OCTEON_SYNCIOBDMA;
    374 	result = octeon_cvmseg_read_8(scraddr);
    375 
    376 	paddr_t addr = result & POW_IOBDMA_GET_WORK_RESULT_ADDR;
    377 
    378 	if (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK)
    379 	    return NULL;
    380 #ifdef __mips_n32
    381 	KASSERT(addr < MIPS_PHYS_MASK);
    382 	return (uint64_t *)MIPS_PHYS_TO_KSEG0(addr);
    383 #else
    384 	return (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(addr);
    385 #endif
    386 }
    387 
    388 static __inline void
    389 octpow_config_int_pc(struct octpow_softc *sc, int unit)
    390 {
    391 	uint64_t wq_int_pc;
    392 	uint64_t pc_thr;
    393 	static uint64_t cpu_clock_hz;
    394 
    395 	if (cpu_clock_hz == 0)
    396 		cpu_clock_hz  = curcpu()->ci_cpu_freq;
    397 
    398 	/* from SDK */
    399 	pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
    400 
    401 	wq_int_pc = __SHIFTIN(pc_thr, POW_WQ_INT_PC_PC_THR);
    402 	_POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
    403 }
    404 
    405 static __inline void
    406 octpow_config_int_pc_rate(struct octpow_softc *sc, int rate)
    407 {
    408 
    409 	octpow_config_int_pc(sc, sc->sc_int_pc_base / rate);
    410 }
    411 
    412 #endif /* !_OCTEON_POWVAR_H_ */
    413