1 /*- 2 * Copyright (C) 2006-2007 Semihalf 3 * All rights reserved. 4 * 5 * Written by: Piotr Kruszynski <ppk@semihalf.com> 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 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 21 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #define TSEC_RX_NUM_DESC 256 33 #define TSEC_TX_NUM_DESC 256 34 35 #define OCP_TSEC_RID_TXIRQ 0 36 #define OCP_TSEC_RID_RXIRQ 1 37 #define OCP_TSEC_RID_ERRIRQ 2 38 39 struct tsec_softc { 40 /* XXX MII bus requires that struct ifnet is first!!! */ 41 struct ifnet *tsec_ifp; 42 43 struct mtx transmit_lock; /* transmitter lock */ 44 struct mtx receive_lock; /* receiver lock */ 45 46 device_t dev; 47 device_t tsec_miibus; 48 struct mii_data *tsec_mii; /* MII media control */ 49 struct callout tsec_tick_ch; 50 int tsec_link; 51 52 bus_dma_tag_t tsec_tx_dtag; /* TX descriptors tag */ 53 bus_dmamap_t tsec_tx_dmap; /* TX descriptors map */ 54 struct tsec_desc *tsec_tx_vaddr;/* vadress of TX descriptors */ 55 uint32_t tsec_tx_raddr; /* real adress of TX descriptors */ 56 57 bus_dma_tag_t tsec_rx_dtag; /* RX descriptors tag */ 58 bus_dmamap_t tsec_rx_dmap; /* RX descriptors map */ 59 struct tsec_desc *tsec_rx_vaddr; /* vadress of RX descriptors */ 60 uint32_t tsec_rx_raddr; /* real adress of RX descriptors */ 61 62 bus_dma_tag_t tsec_tx_mtag; /* TX mbufs tag */ 63 bus_dma_tag_t tsec_rx_mtag; /* TX mbufs tag */ 64 65 struct rx_data_type { 66 bus_dmamap_t map; /* mbuf map */ 67 struct mbuf *mbuf; 68 uint32_t paddr; /* DMA addres of buffer */ 69 } rx_data[TSEC_RX_NUM_DESC]; 70 71 uint32_t tx_cur_desc_cnt; 72 uint32_t tx_dirty_desc_cnt; 73 uint32_t rx_cur_desc_cnt; 74 75 struct resource *sc_rres; /* register resource */ 76 int sc_rrid; /* register rid */ 77 struct { 78 bus_space_tag_t bst; 79 bus_space_handle_t bsh; 80 } sc_bas; 81 82 struct resource *sc_transmit_ires; 83 void *sc_transmit_ihand; 84 int sc_transmit_irid; 85 struct resource *sc_receive_ires; 86 void *sc_receive_ihand; 87 int sc_receive_irid; 88 struct resource *sc_error_ires; 89 void *sc_error_ihand; 90 int sc_error_irid; 91 92 int tsec_if_flags; 93 94 /* TX maps */ 95 bus_dmamap_t tx_map_data[TSEC_TX_NUM_DESC]; 96 97 /* unused TX maps data */ 98 uint32_t tx_map_unused_get_cnt; 99 uint32_t tx_map_unused_put_cnt; 100 bus_dmamap_t *tx_map_unused_data[TSEC_TX_NUM_DESC]; 101 102 /* used TX maps data */ 103 uint32_t tx_map_used_get_cnt; 104 uint32_t tx_map_used_put_cnt; 105 bus_dmamap_t *tx_map_used_data[TSEC_TX_NUM_DESC]; 106 107 /* mbufs in TX queue */ 108 uint32_t tx_mbuf_used_get_cnt; 109 uint32_t tx_mbuf_used_put_cnt; 110 struct mbuf *tx_mbuf_used_data[TSEC_TX_NUM_DESC]; 111 }; 112 113 /* interface to get/put generic objects */ 114 #define TSEC_CNT_INIT(cnt, wrap) ((cnt) = ((wrap) - 1)) 115 116 #define TSEC_INC(count, wrap) (count = ((count) + 1) & ((wrap) - 1)) 117 118 #define TSEC_GET_GENERIC(hand, tab, count, wrap) \ 119 ((hand)->tab[TSEC_INC((hand)->count, wrap)]) 120 121 #define TSEC_PUT_GENERIC(hand, tab, count, wrap, val) \ 122 ((hand)->tab[TSEC_INC((hand)->count, wrap)] = val) 123 124 #define TSEC_BACK_GENERIC(sc, count, wrap) do { \ 125 if ((sc)->count > 0) \ 126 (sc)->count--; \ 127 else \ 128 (sc)->count = (wrap) - 1; \ 129 } while (0) 130 131 /* TX maps interface */ 132 #define TSEC_TX_MAP_CNT_INIT(sc) do { \ 133 TSEC_CNT_INIT((sc)->tx_map_unused_get_cnt, TSEC_TX_NUM_DESC); \ 134 TSEC_CNT_INIT((sc)->tx_map_unused_put_cnt, TSEC_TX_NUM_DESC); \ 135 TSEC_CNT_INIT((sc)->tx_map_used_get_cnt, TSEC_TX_NUM_DESC); \ 136 TSEC_CNT_INIT((sc)->tx_map_used_put_cnt, TSEC_TX_NUM_DESC); \ 137 } while (0) 138 139 /* interface to get/put unused TX maps */ 140 #define TSEC_ALLOC_TX_MAP(sc) \ 141 TSEC_GET_GENERIC(sc, tx_map_unused_data, tx_map_unused_get_cnt, \ 142 TSEC_TX_NUM_DESC) 143 144 #define TSEC_FREE_TX_MAP(sc, val) \ 145 TSEC_PUT_GENERIC(sc, tx_map_unused_data, tx_map_unused_put_cnt, \ 146 TSEC_TX_NUM_DESC, val) 147 148 /* interface to get/put used TX maps */ 149 #define TSEC_GET_TX_MAP(sc) \ 150 TSEC_GET_GENERIC(sc, tx_map_used_data, tx_map_used_get_cnt, \ 151 TSEC_TX_NUM_DESC) 152 153 #define TSEC_PUT_TX_MAP(sc, val) \ 154 TSEC_PUT_GENERIC(sc, tx_map_used_data, tx_map_used_put_cnt, \ 155 TSEC_TX_NUM_DESC, val) 156 157 /* interface to get/put TX mbufs in send queue */ 158 #define TSEC_TX_MBUF_CNT_INIT(sc) do { \ 159 TSEC_CNT_INIT((sc)->tx_mbuf_used_get_cnt, TSEC_TX_NUM_DESC); \ 160 TSEC_CNT_INIT((sc)->tx_mbuf_used_put_cnt, TSEC_TX_NUM_DESC); \ 161 } while (0) 162 163 #define TSEC_GET_TX_MBUF(sc) \ 164 TSEC_GET_GENERIC(sc, tx_mbuf_used_data, tx_mbuf_used_get_cnt, \ 165 TSEC_TX_NUM_DESC) 166 167 #define TSEC_PUT_TX_MBUF(sc, val) \ 168 TSEC_PUT_GENERIC(sc, tx_mbuf_used_data, tx_mbuf_used_put_cnt, \ 169 TSEC_TX_NUM_DESC, val) 170 171 #define TSEC_EMPTYQ_TX_MBUF(sc) \ 172 ((sc)->tx_mbuf_used_get_cnt == (sc)->tx_mbuf_used_put_cnt) 173 174 /* interface for manage tx tsec_desc */ 175 #define TSEC_TX_DESC_CNT_INIT(sc) do { \ 176 TSEC_CNT_INIT((sc)->tx_cur_desc_cnt, TSEC_TX_NUM_DESC); \ 177 TSEC_CNT_INIT((sc)->tx_dirty_desc_cnt, TSEC_TX_NUM_DESC); \ 178 } while (0) 179 180 #define TSEC_GET_CUR_TX_DESC(sc) \ 181 &TSEC_GET_GENERIC(sc, tsec_tx_vaddr, tx_cur_desc_cnt, \ 182 TSEC_TX_NUM_DESC) 183 184 #define TSEC_GET_DIRTY_TX_DESC(sc) \ 185 &TSEC_GET_GENERIC(sc, tsec_tx_vaddr, tx_dirty_desc_cnt, \ 186 TSEC_TX_NUM_DESC) 187 188 #define TSEC_BACK_DIRTY_TX_DESC(sc) \ 189 TSEC_BACK_GENERIC(sc, tx_dirty_desc_cnt, TSEC_TX_NUM_DESC) 190 191 #define TSEC_CUR_DIFF_DIRTY_TX_DESC(sc) \ 192 ((sc)->tx_cur_desc_cnt != (sc)->tx_dirty_desc_cnt) 193 194 #define TSEC_FREE_TX_DESC(sc) \ 195 (((sc)->tx_cur_desc_cnt < (sc)->tx_dirty_desc_cnt) ? \ 196 ((sc)->tx_dirty_desc_cnt - (sc)->tx_cur_desc_cnt - 1) \ 197 : \ 198 (TSEC_TX_NUM_DESC - (sc)->tx_cur_desc_cnt \ 199 + (sc)->tx_dirty_desc_cnt - 1)) 200 201 /* interface for manage rx tsec_desc */ 202 #define TSEC_RX_DESC_CNT_INIT(sc) do { \ 203 TSEC_CNT_INIT((sc)->rx_cur_desc_cnt, TSEC_RX_NUM_DESC); \ 204 } while (0) 205 206 #define TSEC_GET_CUR_RX_DESC(sc) \ 207 &TSEC_GET_GENERIC(sc, tsec_rx_vaddr, rx_cur_desc_cnt, \ 208 TSEC_RX_NUM_DESC) 209 210 #define TSEC_BACK_CUR_RX_DESC(sc) \ 211 TSEC_BACK_GENERIC(sc, rx_cur_desc_cnt, TSEC_RX_NUM_DESC) 212 213 #define TSEC_GET_CUR_RX_DESC_CNT(sc) \ 214 ((sc)->rx_cur_desc_cnt) 215 216 /* init all counters (for init only!) */ 217 #define TSEC_TX_RX_COUNTERS_INIT(sc) do { \ 218 TSEC_TX_MAP_CNT_INIT(sc); \ 219 TSEC_TX_MBUF_CNT_INIT(sc); \ 220 TSEC_TX_DESC_CNT_INIT(sc); \ 221 TSEC_RX_DESC_CNT_INIT(sc); \ 222 } while (0) 223 224 /* read/write bus functions */ 225 #define TSEC_READ(sc, reg) \ 226 bus_space_read_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg)) 227 #define TSEC_WRITE(sc, reg, val) \ 228 bus_space_write_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg), (val)) 229 230 /* Lock for transmitter */ 231 #define TSEC_TRANSMIT_LOCK(sc) do { \ 232 mtx_assert(&(sc)->receive_lock, MA_NOTOWNED); \ 233 mtx_lock(&(sc)->transmit_lock); \ 234 } while (0) 235 236 #define TSEC_TRANSMIT_UNLOCK(sc) mtx_unlock(&(sc)->transmit_lock) 237 #define TSEC_TRANSMIT_LOCK_ASSERT(sc) mtx_assert(&(sc)->transmit_lock, MA_OWNED) 238 239 /* Lock for receiver */ 240 #define TSEC_RECEIVE_LOCK(sc) do { \ 241 mtx_assert(&(sc)->transmit_lock, MA_NOTOWNED); \ 242 mtx_lock(&(sc)->receive_lock); \ 243 } while (0) 244 245 #define TSEC_RECEIVE_UNLOCK(sc) mtx_unlock(&(sc)->receive_lock) 246 #define TSEC_RECEIVE_LOCK_ASSERT(sc) mtx_assert(&(sc)->receive_lock, MA_OWNED) 247 248 /* Global tsec lock (with all locks) */ 249 #define TSEC_GLOBAL_LOCK(sc) do { \ 250 if ((mtx_owned(&(sc)->transmit_lock) ? 1 : 0) != \ 251 (mtx_owned(&(sc)->receive_lock) ? 1 : 0)) { \ 252 panic("tsec deadlock possibility detection!"); \ 253 } \ 254 mtx_lock(&(sc)->transmit_lock); \ 255 mtx_lock(&(sc)->receive_lock); \ 256 } while (0) 257 258 #define TSEC_GLOBAL_UNLOCK(sc) do { \ 259 TSEC_RECEIVE_UNLOCK(sc); \ 260 TSEC_TRANSMIT_UNLOCK(sc); \ 261 } while (0) 262 263 #define TSEC_GLOBAL_LOCK_ASSERT(sc) do { \ 264 TSEC_TRANSMIT_LOCK_ASSERT(sc); \ 265 TSEC_RECEIVE_LOCK_ASSERT(sc); \ 266 } while (0) 267 268 /* From global to {transmit,receive} */ 269 #define TSEC_GLOBAL_TO_TRANSMIT_LOCK(sc) do { \ 270 mtx_unlock(&(sc)->receive_lock);\ 271 } while (0) 272 273 #define TSEC_GLOBAL_TO_RECEIVE_LOCK(sc) do { \ 274 mtx_unlock(&(sc)->transmit_lock);\ 275 } while (0) 276 277 struct tsec_desc { 278 volatile uint16_t flags; /* descriptor flags */ 279 volatile uint16_t length; /* buffer length */ 280 volatile uint32_t bufptr; /* buffer pointer */ 281 }; 282 283 #define TSEC_READ_RETRY 10000 284 #define TSEC_READ_DELAY 100 285