Home | History | Annotate | Line # | Download | only in dev
octeon_powvar.h revision 1.1
      1 /*	$NetBSD: octeon_powvar.h,v 1.1 2015/04/29 08:32:01 hikaru 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 #define POW_TAG_TYPE_ORDERED	0
     35 #define POW_TAG_TYPE_ATOMIC	1
     36 #define POW_TAG_TYPE_NULL	2
     37 #define POW_TAG_TYPE_NULL_NULL	3
     38 
     39 #define POW_TAG_OP_SWTAG		0
     40 #define POW_TAG_OP_SWTAG_FULL		1
     41 #define POW_TAG_OP_SWTAG_DESCHED	2
     42 #define POW_TAG_OP_DESCHED		3
     43 #define POW_TAG_OP_ADDWQ		4
     44 #define POW_TAG_OP_UPD_WQP_GRP		5
     45 #define POW_TAG_OP_CLR_NSCHED		7
     46 #define POW_TAG_OP_NOP			15
     47 
     48 #define POW_WAIT	1
     49 #define POW_NO_WAIT	0
     50 
     51 /* XXX */
     52 struct octeon_pow_softc {
     53 	device_t		sc_dev;
     54 	bus_space_tag_t		sc_regt;
     55 	bus_space_handle_t	sc_regh;
     56 	int			sc_port;
     57 	int			sc_int_pc_base;
     58 #ifdef OCTEON_ETH_DEBUG
     59 	struct evcnt		sc_ev_powecciopcsrpend;
     60 	struct evcnt		sc_ev_powecciopdbgpend;
     61 	struct evcnt		sc_ev_powecciopaddwork;
     62 	struct evcnt		sc_ev_powecciopillop;
     63 	struct evcnt		sc_ev_poweccioppend24;
     64 	struct evcnt		sc_ev_poweccioppend23;
     65 	struct evcnt		sc_ev_poweccioppend22;
     66 	struct evcnt		sc_ev_poweccioppend21;
     67 	struct evcnt		sc_ev_poweccioptagnull;
     68 	struct evcnt		sc_ev_poweccioptagnullnull;
     69 	struct evcnt		sc_ev_powecciopordatom;
     70 	struct evcnt		sc_ev_powecciopnull;
     71 	struct evcnt		sc_ev_powecciopnullnull;
     72 	struct evcnt		sc_ev_poweccrpe;
     73 	struct evcnt		sc_ev_poweccsyn;
     74 	struct evcnt		sc_ev_poweccdbe;
     75 	struct evcnt		sc_ev_poweccsbe;
     76 #endif
     77 };
     78 
     79 /* XXX */
     80 struct octeon_pow_attach_args {
     81 	int			aa_port;
     82 	bus_space_tag_t		aa_regt;
     83 };
     84 
     85 void			octeon_pow_config(struct octeon_pow_softc *, int);
     86 void			*octeon_pow_intr_establish(int, int,
     87 			    void (*)(void *, uint64_t *),
     88 			    void (*)(int *, int *, uint64_t, void *),
     89 			    void *);
     90 void			octeon_pow_error_int_enable(void *, int);
     91 uint64_t		octeon_pow_error_int_summary(void *);
     92 int			octeon_pow_ring_reduce(void *);
     93 int			octeon_pow_ring_grow(void *);
     94 int			octeon_pow_ring_size(void);
     95 int			octeon_pow_ring_intr(void);
     96 
     97 #define	_POW_RD8(sc, off) \
     98 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
     99 #define	_POW_WR8(sc, off, v) \
    100 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
    101 #define	_POW_GROUP_RD8(sc, pi, off) \
    102 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
    103 	    (off) + sizeof(uint64_t) * (pi)->pi_group)
    104 #define	_POW_GROUP_WR8(sc, pi, off, v) \
    105 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
    106 	    (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
    107 
    108 extern struct octeon_pow_softc	octeon_pow_softc;
    109 
    110 /* -------------------------------------------------------------------------- */
    111 
    112 /* Load Operations */
    113 
    114 /* GET_WORK Loads */
    115 
    116 static inline uint64_t
    117 octeon_pow_ops_get_work_load(
    118 	int wait)			/* 0-1 */
    119 {
    120 	uint64_t ptr =
    121 	    POW_OPERATION_BASE_IO_BIT |
    122 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    123 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x00) |
    124 	    __BITS64_SET(POW_GET_WORK_LOAD_WAIT, wait);
    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 octeon_pow_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 	    POW_OPERATION_BASE_IO_BIT |
    149 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    150 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x01) |
    151 	    __BITS64_SET(POW_STATUS_LOAD_COREID, coreid) |
    152 	    __BITS64_SET(POW_STATUS_LOAD_GET_REV, get_rev) |
    153 	    __BITS64_SET(POW_STATUS_LOAD_GET_CUR, get_cur) |
    154 	    __BITS64_SET(POW_STATUS_LOAD_GET_WQP, get_wqp);
    155 
    156 	return octeon_xkphys_read_8(ptr);
    157 }
    158 
    159 /* POW Memory Loads */
    160 
    161 /*
    162  * a) get_des == 0, get_wqp == 0 (tag)
    163  * b) get_des == 0, get_wqp == 1 (wqe)
    164  * c) get_des == 1 (desched)
    165  */
    166 
    167 static inline uint64_t
    168 octeon_pow_ops_pow_memory(
    169 	int index,			/* 0-2047 */
    170 	int get_des,			/* 0-1 */
    171 	int get_wqp)			/* 0-1 */
    172 {
    173 	uint64_t ptr =
    174 	    POW_OPERATION_BASE_IO_BIT |
    175 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    176 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x02) |
    177 	    __BITS64_SET(POW_MEMORY_LOAD_INDEX, index) |
    178 	    __BITS64_SET(POW_MEMORY_LOAD_GET_DES, get_des) |
    179 	    __BITS64_SET(POW_MEMORY_LOAD_GET_WQP, get_wqp);
    180 
    181 	return octeon_xkphys_read_8(ptr);
    182 }
    183 
    184 /* POW Index/Pointer Loads */
    185 
    186 /*
    187  * a) get_rmt == 0, get_des_get_tail == 0
    188  * b) get_rmt == 0, get_des_get_tail == 1
    189  * c) get_rmt == 1, get_des_get_tail == 0
    190  * d) get_rmt == 1, get_des_get_tail == 1
    191  */
    192 
    193 static inline uint64_t
    194 octeon_pow_ops_pow_idxptr(
    195 	int qosgrp,			/* 0-7 */
    196 	int get_des_get_tail,		/* 0-1 */
    197 	int get_rmt)			/* 0-1 */
    198 {
    199 	uint64_t ptr =
    200 	    POW_OPERATION_BASE_IO_BIT |
    201 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    202 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x03) |
    203 	    __BITS64_SET(POW_IDXPTR_LOAD_QOSGRP, qosgrp) |
    204 	    __BITS64_SET(POW_IDXPTR_LOAD_GET_DES_GET_TAIL, get_des_get_tail) |
    205 	    __BITS64_SET(POW_IDXPTR_LOAD_GET_RMT, get_rmt);
    206 
    207 	return octeon_xkphys_read_8(ptr);
    208 }
    209 
    210 /* NULL_RD Loads */
    211 
    212 static inline uint64_t
    213 octeon_pow_ops_null_rd_load(void)
    214 {
    215 	uint64_t ptr =
    216 	    POW_OPERATION_BASE_IO_BIT |
    217 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    218 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x04);
    219 
    220 	return octeon_xkphys_read_8(ptr);
    221 }
    222 
    223 /* IOBDMA Operations */
    224 
    225 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
    226 
    227 /* The ``scraddr'' part is index in 8 byte words, not address. */
    228 
    229 /* GET_WORK IOBDMAs */
    230 
    231 static inline void
    232 octeon_pow_ops_get_work_iobdma(
    233 	int scraddr,			/* 0-2047 */
    234 	int wait)			/* 0-1 */
    235 {
    236  	/* ``scraddr'' part is index in 64-bit words, not address */
    237 	const int scrindex = scraddr / sizeof(uint64_t);
    238 
    239         uint64_t args =
    240              __BITS64_SET(POW_IOBDMA_GET_WORK_WAIT, wait);
    241         uint64_t value =
    242             __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
    243             __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
    244             __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
    245             __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x00) |
    246             __BITS64_SET(POW_IOBDMA_BASE_39_0, args);
    247 
    248         octeon_iobdma_write_8(value);
    249 }
    250 
    251 /* NULL_RD IOBDMAs */
    252 
    253 static inline void
    254 octeon_pow_ops_null_rd_iobdma(
    255 	int scraddr)			/* 0-2047 */
    256 {
    257  	/* ``scraddr'' part is index in 64-bit words, not address */
    258 	const int scrindex = scraddr / sizeof(uint64_t);
    259 
    260         uint64_t value =
    261             __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
    262             __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
    263             __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
    264             __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x04) |
    265             __BITS64_SET(POW_IOBDMA_BASE_39_0, 0);
    266 
    267         octeon_iobdma_write_8(value);
    268 }
    269 
    270 /* Store Operations */
    271 
    272 static inline void
    273 octeon_pow_store(
    274 	int subdid,			/* 0, 1, 3 */
    275 	uint64_t addr,			/* 0-0x0000.000f.ffff.ffff */
    276 	int no_sched,			/* 0, 1 */
    277 	int index,			/* 0-8191 */
    278 	int op,				/* 0-15 */
    279 	int qos,			/* 0-7 */
    280 	int grp,			/* 0-7 */
    281 	int type,			/* 0-7 */
    282 	uint32_t tag)			/* 0-0xffff.ffff */
    283 {
    284 	/* Physical Address to Store to POW */
    285 	uint64_t ptr =
    286 	    POW_OPERATION_BASE_IO_BIT |
    287 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
    288 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, subdid) |
    289 	    __BITS64_SET(POW_PHY_ADDR_STORE_ADDR, addr);
    290 
    291 	/* Store Data on Store to POW */
    292 	uint64_t args =
    293 	    __BITS64_SET(POW_STORE_DATA_NO_SCHED, no_sched) |
    294 	    __BITS64_SET(POW_STORE_DATA_INDEX, index) |
    295 	    __BITS64_SET(POW_STORE_DATA_OP, op) |
    296 	    __BITS64_SET(POW_STORE_DATA_QOS, qos) |
    297 	    __BITS64_SET(POW_STORE_DATA_GRP, grp) |
    298 	    __BITS64_SET(POW_STORE_DATA_TYPE, type) |
    299 	    __BITS64_SET(POW_STORE_DATA_TAG, tag);
    300 
    301 	octeon_xkphys_write_8(ptr, args);
    302 }
    303 
    304 /* SWTAG */
    305 
    306 static inline void
    307 octeon_pow_ops_swtag(int type, uint32_t tag)
    308 {
    309 	octeon_pow_store(
    310 		1,			/* subdid == 1 */
    311 		0, 			/* addr (not used for SWTAG) */
    312 		0,			/* no_sched (not used for SWTAG) */
    313 		0,			/* index (not used for SWTAG) */
    314 		POW_TAG_OP_SWTAG,	/* op == SWTAG */
    315 		0,			/* qos (not used for SWTAG) */
    316 		0,			/* grp (not used for SWTAG) */
    317 		type,
    318 		tag);
    319 	/* switch to NULL completes immediately */
    320 }
    321 
    322 /* SWTAG_FULL */
    323 
    324 static inline void
    325 octeon_pow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
    326 {
    327 	octeon_pow_store(
    328 		0,			/* subdid == 0 */
    329 		addr,
    330 		0,			/* no_sched (not used for SWTAG_FULL) */
    331 		0,			/* index (not used for SWTAG_FULL) */
    332 		POW_TAG_OP_SWTAG_FULL,	/* op == SWTAG_FULL */
    333 		0,			/* qos (not used for SWTAG_FULL) */
    334 		grp,
    335 		type,
    336 		tag);
    337 }
    338 
    339 /* SWTAG_DESCHED */
    340 
    341 static inline void
    342 octeon_pow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
    343 {
    344 	octeon_pow_store(
    345 		3,			/* subdid == 3 */
    346 		0,			/* addr (not used for SWTAG_DESCHED) */
    347 		no_sched,
    348 		0,			/* index (not used for SWTAG_DESCHED) */
    349 		POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
    350 		0,			/* qos (not used for SWTAG_DESCHED) */
    351 		grp,
    352 		type,
    353 		tag);
    354 }
    355 
    356 /* DESCHED */
    357 
    358 static inline void
    359 octeon_pow_ops_desched(int no_sched)
    360 {
    361 	octeon_pow_store(
    362 		3,			/* subdid == 3 */
    363 		0,			/* addr (not used for DESCHED) */
    364 		no_sched,
    365 		0,			/* index (not used for DESCHED) */
    366 		POW_TAG_OP_DESCHED,	/* op == DESCHED */
    367 		0,			/* qos (not used for DESCHED) */
    368 		0,			/* grp (not used for DESCHED) */
    369 		0,			/* type (not used for DESCHED) */
    370 		0);			/* tag (not used for DESCHED) */
    371 }
    372 
    373 /* ADDWQ */
    374 
    375 static inline void
    376 octeon_pow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
    377 {
    378 	octeon_pow_store(
    379 		1,			/* subdid == 1 */
    380 		addr,
    381 		0,			/* no_sched (not used for ADDWQ) */
    382 		0,			/* index (not used for ADDWQ) */
    383 		POW_TAG_OP_ADDWQ,	/* op == ADDWQ */
    384 		qos,
    385 		grp,
    386 		type,
    387 		tag);
    388 }
    389 
    390 /* UPD_WQP_GRP */
    391 
    392 static inline void
    393 octeon_pow_ops_upd_wqp_grp(paddr_t addr, int grp)
    394 {
    395 	octeon_pow_store(
    396 		1,			/* subdid == 1 */
    397 		addr,
    398 		0,			/* no_sched (not used for UPD_WQP_GRP) */
    399 		0,			/* index (not used for UPD_WQP_GRP) */
    400 		POW_TAG_OP_UPD_WQP_GRP,	/* op == UPD_WQP_GRP */
    401 		0,			/* qos (not used for UPD_WQP_GRP) */
    402 		grp,
    403 		0,			/* type (not used for UPD_WQP_GRP) */
    404 		0);			/* tag (not used for UPD_WQP_GRP) */
    405 }
    406 
    407 /* CLR_NSCHED */
    408 
    409 static inline void
    410 octeon_pow_ops_clr_nsched(paddr_t addr, int index)
    411 {
    412 	octeon_pow_store(
    413 		1,			/* subdid == 1 */
    414 		addr,
    415 		0,			/* no_sched (not used for CLR_NSCHED) */
    416 		index,
    417 		POW_TAG_OP_CLR_NSCHED,	/* op == CLR_NSCHED */
    418 		0,			/* qos (not used for CLR_NSCHED) */
    419 		0,			/* grp (not used for CLR_NSCHED) */
    420 		0,			/* type (not used for CLR_NSCHED) */
    421 		0);			/* tag (not used for CLR_NSCHED) */
    422 }
    423 
    424 /* NOP */
    425 
    426 static inline void
    427 octeon_pow_ops_nop(void)
    428 {
    429 	octeon_pow_store(
    430 		1,			/* subdid == 1 */
    431 		0,			/* addr (not used for NOP) */
    432 		0,			/* no_sched (not used for NOP) */
    433 		0,			/* index (not used for NOP) */
    434 		POW_TAG_OP_NOP,		/* op == NOP */
    435 		0,			/* qos (not used for NOP) */
    436 		0,			/* grp (not used for NOP) */
    437 		0,			/* type (not used for NOP) */
    438 		0);			/* tag (not used for NOP) */
    439 }
    440 
    441 /* -------------------------------------------------------------------------- */
    442 
    443 /*
    444  * global functions
    445  */
    446 static inline void
    447 octeon_pow_work_request_async(uint64_t scraddr, uint64_t wait)
    448 {
    449         octeon_pow_ops_get_work_iobdma(scraddr, wait);
    450 }
    451 
    452 static inline uint64_t *
    453 octeon_pow_work_response_async(uint64_t scraddr)
    454 {
    455 	uint64_t result;
    456 
    457 	OCTEON_SYNCIOBDMA;
    458 	result = octeon_cvmseg_read_8(scraddr);
    459 
    460 	return (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK) ?
    461 	    NULL :
    462 	    (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(
    463 		result & POW_IOBDMA_GET_WORK_RESULT_ADDR);
    464 }
    465 
    466 static inline void
    467 octeon_pow_config_int_pc(struct octeon_pow_softc *sc, int unit)
    468 {
    469 	uint64_t wq_int_pc;
    470 	uint64_t pc_thr;
    471 	static uint64_t cpu_clock_hz;
    472 
    473 	if (cpu_clock_hz == 0)
    474 		cpu_clock_hz  = curcpu()->ci_cpu_freq;
    475 
    476 	/* from SDK */
    477 	pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
    478 
    479 	wq_int_pc = pc_thr << POW_WQ_INT_PC_PC_THR_SHIFT;
    480 	_POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
    481 }
    482 
    483 static inline void
    484 octeon_pow_config_int_pc_rate(struct octeon_pow_softc *sc, int rate)
    485 {
    486 	octeon_pow_config_int_pc(sc, sc->sc_int_pc_base / rate);
    487 }
    488 
    489 /* wait until ready */
    490 static inline void
    491 octeon_pow_tag_sw_wait(void)
    492 {
    493 	__asm __volatile (
    494 		"	.set	push		\n"
    495 		"	.set	noreorder	\n"
    496 		"	.set	arch=octeon	\n"
    497 		"1:	rdhwr	$2, $30		\n"
    498 		"	beqz	$2, 1b		\n"
    499 		"	 nop			\n"
    500 		"	.set	pop		\n"
    501 	);
    502 }
    503 
    504 #endif /* _OCTEON_POWVAR_H_ */
    505