Home | History | Annotate | Line # | Download | only in dev
octeon_powvar.h revision 1.5
      1 /*	$NetBSD: octeon_powvar.h,v 1.5 2020/06/18 13:52:08 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 /* XXX */
     54 struct octpow_softc {
     55 	device_t		sc_dev;
     56 	bus_space_tag_t		sc_regt;
     57 	bus_space_handle_t	sc_regh;
     58 	int			sc_port;
     59 	int			sc_int_pc_base;
     60 #ifdef CNMAC_DEBUG
     61 	struct evcnt		sc_ev_powecciopcsrpend;
     62 	struct evcnt		sc_ev_powecciopdbgpend;
     63 	struct evcnt		sc_ev_powecciopaddwork;
     64 	struct evcnt		sc_ev_powecciopillop;
     65 	struct evcnt		sc_ev_poweccioppend24;
     66 	struct evcnt		sc_ev_poweccioppend23;
     67 	struct evcnt		sc_ev_poweccioppend22;
     68 	struct evcnt		sc_ev_poweccioppend21;
     69 	struct evcnt		sc_ev_poweccioptagnull;
     70 	struct evcnt		sc_ev_poweccioptagnullnull;
     71 	struct evcnt		sc_ev_powecciopordatom;
     72 	struct evcnt		sc_ev_powecciopnull;
     73 	struct evcnt		sc_ev_powecciopnullnull;
     74 	struct evcnt		sc_ev_poweccrpe;
     75 	struct evcnt		sc_ev_poweccsyn;
     76 	struct evcnt		sc_ev_poweccdbe;
     77 	struct evcnt		sc_ev_poweccsbe;
     78 #endif
     79 };
     80 
     81 /* XXX */
     82 struct octpow_attach_args {
     83 	int			aa_port;
     84 	bus_space_tag_t		aa_regt;
     85 };
     86 
     87 void			octpow_config(struct octpow_softc *, int);
     88 void			*octpow_intr_establish(int, int,
     89 			    void (*)(void *, uint64_t *),
     90 			    void (*)(int *, int *, uint64_t, void *),
     91 			    void *);
     92 void			octpow_error_int_enable(void *, int);
     93 uint64_t		octpow_error_int_summary(void *);
     94 int			octpow_ring_reduce(void *);
     95 int			octpow_ring_grow(void *);
     96 int			octpow_ring_size(void);
     97 int			octpow_ring_intr(void);
     98 
     99 #define	_POW_RD8(sc, off) \
    100 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
    101 #define	_POW_WR8(sc, off, v) \
    102 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
    103 #define	_POW_GROUP_RD8(sc, pi, off) \
    104 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
    105 	    (off) + sizeof(uint64_t) * (pi)->pi_group)
    106 #define	_POW_GROUP_WR8(sc, pi, off, v) \
    107 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
    108 	    (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
    109 
    110 extern struct octpow_softc	octpow_softc;
    111 
    112 /* -------------------------------------------------------------------------- */
    113 
    114 /* Load Operations */
    115 
    116 /* GET_WORK Loads */
    117 
    118 static __inline uint64_t
    119 octpow_ops_get_work_load(
    120 	int wait)			/* 0-1 */
    121 {
    122 	uint64_t ptr =
    123 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_GET_WORK) |
    124 	    (wait ? POW_GET_WORK_LOAD_WAIT : 0);
    125 
    126 	return octeon_xkphys_read_8(ptr);
    127 }
    128 
    129 /* POW Status Loads */
    130 
    131 /*
    132  * a) get_cur == 0, get_wqp == 0 (pend_tag)
    133  * b) get_cur == 0, get_wqp == 1 (pend_wqp)
    134  * c) get_cur == 1, get_wqp == 0, get_rev == 0 (cur_tag_next)
    135  * d) get_cur == 1, get_wqp == 0, get_rev == 1 (cur_tag_prev)
    136  * e) get_cur == 1, get_wqp == 1, get_rev == 0 (cur_wqp_next)
    137  * f) get_cur == 1, get_wqp == 1, get_rev == 1 (cur_wqp_prev)
    138  */
    139 
    140 static __inline uint64_t
    141 octpow_ops_pow_status(
    142 	int coreid,			/* 0-15 */
    143 	int get_rev,			/* 0-1 */
    144 	int get_cur,			/* 0-1 */
    145 	int get_wqp)			/* 0-1 */
    146 {
    147 	uint64_t ptr =
    148 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_STATUS_LOAD) |
    149 	    __SHIFTIN(coreid, POW_STATUS_LOAD_COREID) |
    150 	    __SHIFTIN(get_rev, POW_STATUS_LOAD_GET_REV) |
    151 	    __SHIFTIN(get_cur, POW_STATUS_LOAD_GET_CUR) |
    152 	    __SHIFTIN(get_wqp, POW_STATUS_LOAD_GET_WQP);
    153 
    154 	return octeon_xkphys_read_8(ptr);
    155 }
    156 
    157 /* POW Memory Loads */
    158 
    159 /*
    160  * a) get_des == 0, get_wqp == 0 (tag)
    161  * b) get_des == 0, get_wqp == 1 (wqe)
    162  * c) get_des == 1 (desched)
    163  */
    164 
    165 static __inline uint64_t
    166 octpow_ops_pow_memory(
    167 	int index,			/* 0-2047 */
    168 	int get_des,			/* 0-1 */
    169 	int get_wqp)			/* 0-1 */
    170 {
    171 	uint64_t ptr =
    172 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_MEMORY_LOAD) |
    173 	    __SHIFTIN(index, POW_MEMORY_LOAD_INDEX) |
    174 	    __SHIFTIN(get_des, POW_MEMORY_LOAD_GET_DES) |
    175 	    __SHIFTIN(get_wqp, POW_MEMORY_LOAD_GET_WQP);
    176 
    177 	return octeon_xkphys_read_8(ptr);
    178 }
    179 
    180 /* POW Index/Pointer Loads */
    181 
    182 /*
    183  * a) get_rmt == 0, get_des_get_tail == 0
    184  * b) get_rmt == 0, get_des_get_tail == 1
    185  * c) get_rmt == 1, get_des_get_tail == 0
    186  * d) get_rmt == 1, get_des_get_tail == 1
    187  */
    188 
    189 static __inline uint64_t
    190 octpow_ops_pow_idxptr(
    191 	int qosgrp,			/* 0-7 */
    192 	int get_des_get_tail,		/* 0-1 */
    193 	int get_rmt)			/* 0-1 */
    194 {
    195 	uint64_t ptr =
    196 	    OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_IDXPTR_LOAD) |
    197 	    __SHIFTIN(qosgrp, POW_IDXPTR_LOAD_QOSGRP) |
    198 	    __SHIFTIN(get_des_get_tail, POW_IDXPTR_LOAD_GET_DES_GET_TAIL) |
    199 	    __SHIFTIN(get_rmt, POW_IDXPTR_LOAD_GET_RMT);
    200 
    201 	return octeon_xkphys_read_8(ptr);
    202 }
    203 
    204 /* NULL_RD Loads */
    205 
    206 static __inline uint64_t
    207 octpow_ops_null_rd_load(void)
    208 {
    209 	uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_NULL_RD);
    210 
    211 	return octeon_xkphys_read_8(ptr);
    212 }
    213 
    214 /* IOBDMA Operations */
    215 
    216 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
    217 
    218 /* The ``scraddr'' part is index in 8 byte words, not address. */
    219 
    220 /* GET_WORK IOBDMAs */
    221 
    222 static __inline void
    223 octpow_ops_get_work_iobdma(
    224 	int scraddr,			/* 0-2047 */
    225 	int wait)			/* 0-1 */
    226 {
    227  	/* ``scraddr'' part is index in 64-bit words, not address */
    228 	const int scrindex = scraddr / sizeof(uint64_t);
    229 
    230 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
    231 	    POW_IOBDMA_SUBDID_GET_WORK, scrindex, POW_IOBDMA_LEN,
    232 	    wait ? POW_IOBDMA_GET_WORK_WAIT : 0);
    233 
    234         octeon_iobdma_write_8(value);
    235 }
    236 
    237 /* NULL_RD IOBDMAs */
    238 
    239 static __inline void
    240 octpow_ops_null_rd_iobdma(
    241 	int scraddr)			/* 0-2047 */
    242 {
    243  	/* ``scraddr'' part is index in 64-bit words, not address */
    244 	const int scrindex = scraddr / sizeof(uint64_t);
    245 
    246 	uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
    247 	    POW_IOBDMA_SUBDID_NULL_RD, scrindex, POW_IOBDMA_LEN, 0);
    248 
    249         octeon_iobdma_write_8(value);
    250 }
    251 
    252 /* Store Operations */
    253 
    254 static __inline void
    255 octpow_store(
    256 	int subdid,			/* 0, 1, 3 */
    257 	uint64_t addr,			/* 0-0x0000.000f.ffff.ffff */
    258 	int no_sched,			/* 0, 1 */
    259 	int index,			/* 0-8191 */
    260 	int op,				/* 0-15 */
    261 	int qos,			/* 0-7 */
    262 	int grp,			/* 0-7 */
    263 	int type,			/* 0-7 */
    264 	uint32_t tag)			/* 0-0xffff.ffff */
    265 {
    266 	/* Physical Address to Store to POW */
    267 	uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, subdid) |
    268 	    __SHIFTIN(addr, POW_PHY_ADDR_STORE_ADDR);
    269 
    270 	/* Store Data on Store to POW */
    271 	uint64_t args =
    272 	    __SHIFTIN(no_sched, POW_STORE_DATA_NO_SCHED) |
    273 	    __SHIFTIN(index, POW_STORE_DATA_INDEX) |
    274 	    __SHIFTIN(op, POW_STORE_DATA_OP) |
    275 	    __SHIFTIN(qos, POW_STORE_DATA_QOS) |
    276 	    __SHIFTIN(grp, POW_STORE_DATA_GRP) |
    277 	    __SHIFTIN(type, POW_STORE_DATA_TYPE) |
    278 	    __SHIFTIN(tag, POW_STORE_DATA_TAG);
    279 
    280 	octeon_xkphys_write_8(ptr, args);
    281 }
    282 
    283 /* SWTAG */
    284 
    285 static __inline void
    286 octpow_ops_swtag(int type, uint32_t tag)
    287 {
    288 
    289 	octpow_store(
    290 		POW_STORE_SUBDID_OTHER,
    291 		0, 			/* addr (not used for SWTAG) */
    292 		0,			/* no_sched (not used for SWTAG) */
    293 		0,			/* index (not used for SWTAG) */
    294 		POW_TAG_OP_SWTAG,	/* op == SWTAG */
    295 		0,			/* qos (not used for SWTAG) */
    296 		0,			/* grp (not used for SWTAG) */
    297 		type,
    298 		tag);
    299 	/* switch to NULL completes immediately */
    300 }
    301 
    302 /* SWTAG_FULL */
    303 
    304 static __inline void
    305 octpow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
    306 {
    307 
    308 	octpow_store(
    309 		POW_STORE_SUBDID_SWTAG_FULL,
    310 		addr,
    311 		0,			/* no_sched (not used for SWTAG_FULL) */
    312 		0,			/* index (not used for SWTAG_FULL) */
    313 		POW_TAG_OP_SWTAG_FULL,	/* op == SWTAG_FULL */
    314 		0,			/* qos (not used for SWTAG_FULL) */
    315 		grp,
    316 		type,
    317 		tag);
    318 }
    319 
    320 /* SWTAG_DESCHED */
    321 
    322 static __inline void
    323 octpow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
    324 {
    325 
    326 	octpow_store(
    327 		POW_STORE_SUBDID_DESCHED,
    328 		0,			/* addr (not used for SWTAG_DESCHED) */
    329 		no_sched,
    330 		0,			/* index (not used for SWTAG_DESCHED) */
    331 		POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
    332 		0,			/* qos (not used for SWTAG_DESCHED) */
    333 		grp,
    334 		type,
    335 		tag);
    336 }
    337 
    338 /* DESCHED */
    339 
    340 static __inline void
    341 octpow_ops_desched(int no_sched)
    342 {
    343 
    344 	octpow_store(
    345 		POW_STORE_SUBDID_DESCHED,
    346 		0,			/* addr (not used for DESCHED) */
    347 		no_sched,
    348 		0,			/* index (not used for DESCHED) */
    349 		POW_TAG_OP_DESCHED,	/* op == DESCHED */
    350 		0,			/* qos (not used for DESCHED) */
    351 		0,			/* grp (not used for DESCHED) */
    352 		0,			/* type (not used for DESCHED) */
    353 		0);			/* tag (not used for DESCHED) */
    354 }
    355 
    356 /* ADDWQ */
    357 
    358 static __inline void
    359 octpow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
    360 {
    361 
    362 	octpow_store(
    363 		POW_STORE_SUBDID_OTHER,
    364 		addr,
    365 		0,			/* no_sched (not used for ADDWQ) */
    366 		0,			/* index (not used for ADDWQ) */
    367 		POW_TAG_OP_ADDWQ,	/* op == ADDWQ */
    368 		qos,
    369 		grp,
    370 		type,
    371 		tag);
    372 }
    373 
    374 /* UPD_WQP_GRP */
    375 
    376 static __inline void
    377 octpow_ops_upd_wqp_grp(paddr_t addr, int grp)
    378 {
    379 
    380 	octpow_store(
    381 		POW_STORE_SUBDID_OTHER,
    382 		addr,
    383 		0,			/* no_sched (not used for UPD_WQP_GRP) */
    384 		0,			/* index (not used for UPD_WQP_GRP) */
    385 		POW_TAG_OP_UPD_WQP_GRP,	/* op == UPD_WQP_GRP */
    386 		0,			/* qos (not used for UPD_WQP_GRP) */
    387 		grp,
    388 		0,			/* type (not used for UPD_WQP_GRP) */
    389 		0);			/* tag (not used for UPD_WQP_GRP) */
    390 }
    391 
    392 /* CLR_NSCHED */
    393 
    394 static __inline void
    395 octpow_ops_clr_nsched(paddr_t addr, int index)
    396 {
    397 
    398 	octpow_store(
    399 		POW_STORE_SUBDID_OTHER,
    400 		addr,
    401 		0,			/* no_sched (not used for CLR_NSCHED) */
    402 		index,
    403 		POW_TAG_OP_CLR_NSCHED,	/* op == CLR_NSCHED */
    404 		0,			/* qos (not used for CLR_NSCHED) */
    405 		0,			/* grp (not used for CLR_NSCHED) */
    406 		0,			/* type (not used for CLR_NSCHED) */
    407 		0);			/* tag (not used for CLR_NSCHED) */
    408 }
    409 
    410 /* NOP */
    411 
    412 static __inline void
    413 octpow_ops_nop(void)
    414 {
    415 
    416 	octpow_store(
    417 		POW_STORE_SUBDID_OTHER,
    418 		0,			/* addr (not used for NOP) */
    419 		0,			/* no_sched (not used for NOP) */
    420 		0,			/* index (not used for NOP) */
    421 		POW_TAG_OP_NOP,		/* op == NOP */
    422 		0,			/* qos (not used for NOP) */
    423 		0,			/* grp (not used for NOP) */
    424 		0,			/* type (not used for NOP) */
    425 		0);			/* tag (not used for NOP) */
    426 }
    427 
    428 /* -------------------------------------------------------------------------- */
    429 
    430 /*
    431  * global functions
    432  */
    433 static __inline void
    434 octpow_work_request_async(uint64_t scraddr, uint64_t wait)
    435 {
    436 
    437         octpow_ops_get_work_iobdma(scraddr, wait);
    438 }
    439 
    440 static __inline uint64_t *
    441 octpow_work_response_async(uint64_t scraddr)
    442 {
    443 	uint64_t result;
    444 
    445 	OCTEON_SYNCIOBDMA;
    446 	result = octeon_cvmseg_read_8(scraddr);
    447 
    448 	paddr_t addr = result & POW_IOBDMA_GET_WORK_RESULT_ADDR;
    449 
    450 	if (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK)
    451 	    return NULL;
    452 #ifdef __mips_n32
    453 	KASSERT(addr < MIPS_PHYS_MASK);
    454 	//if (addr < MIPS_PHYS_MASK)
    455 		return (uint64_t *)MIPS_PHYS_TO_KSEG0(addr);
    456 #else
    457 	return (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(addr);
    458 #endif
    459 }
    460 
    461 static __inline void
    462 octpow_config_int_pc(struct octpow_softc *sc, int unit)
    463 {
    464 	uint64_t wq_int_pc;
    465 	uint64_t pc_thr;
    466 	static uint64_t cpu_clock_hz;
    467 
    468 	if (cpu_clock_hz == 0)
    469 		cpu_clock_hz  = curcpu()->ci_cpu_freq;
    470 
    471 	/* from SDK */
    472 	pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
    473 
    474 	wq_int_pc = __SHIFTIN(pc_thr, POW_WQ_INT_PC_PC_THR);
    475 	_POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
    476 }
    477 
    478 static __inline void
    479 octpow_config_int_pc_rate(struct octpow_softc *sc, int rate)
    480 {
    481 
    482 	octpow_config_int_pc(sc, sc->sc_int_pc_base / rate);
    483 }
    484 
    485 /* wait until ready */
    486 static __inline void
    487 octpow_tag_sw_wait(void)
    488 {
    489 	__asm __volatile (
    490 		"	.set	push		\n"
    491 		"	.set	noreorder	\n"
    492 		"	.set	arch=octeon	\n"
    493 		"1:	rdhwr	$2, $30		\n"
    494 		"	beqz	$2, 1b		\n"
    495 		"	 nop			\n"
    496 		"	.set	pop		\n"
    497 	);
    498 }
    499 
    500 #endif /* _OCTEON_POWVAR_H_ */
    501