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 /* Watchdog related */ 95 struct callout wd_callout; 96 int wd_timer; 97 98 /* TX maps */ 99 bus_dmamap_t tx_map_data[TSEC_TX_NUM_DESC]; 100 101 /* unused TX maps data */ 102 uint32_t tx_map_unused_get_cnt; 103 uint32_t tx_map_unused_put_cnt; 104 bus_dmamap_t *tx_map_unused_data[TSEC_TX_NUM_DESC]; 105 106 /* used TX maps data */ 107 uint32_t tx_map_used_get_cnt; 108 uint32_t tx_map_used_put_cnt; 109 bus_dmamap_t *tx_map_used_data[TSEC_TX_NUM_DESC]; 110 111 /* mbufs in TX queue */ 112 uint32_t tx_mbuf_used_get_cnt; 113 uint32_t tx_mbuf_used_put_cnt; 114 struct mbuf *tx_mbuf_used_data[TSEC_TX_NUM_DESC]; 115 }; 116 117 /* interface to get/put generic objects */ 118 #define TSEC_CNT_INIT(cnt, wrap) ((cnt) = ((wrap) - 1)) 119 120 #define TSEC_INC(count, wrap) (count = ((count) + 1) & ((wrap) - 1)) 121 122 #define TSEC_GET_GENERIC(hand, tab, count, wrap) \ 123 ((hand)->tab[TSEC_INC((hand)->count, wrap)]) 124 125 #define TSEC_PUT_GENERIC(hand, tab, count, wrap, val) \ 126 ((hand)->tab[TSEC_INC((hand)->count, wrap)] = val) 127 128 #define TSEC_BACK_GENERIC(sc, count, wrap) do { \ 129 if ((sc)->count > 0) \ 130 (sc)->count--; \ 131 else \ 132 (sc)->count = (wrap) - 1; \ 133 } while (0) 134 135 /* TX maps interface */ 136 #define TSEC_TX_MAP_CNT_INIT(sc) do { \ 137 TSEC_CNT_INIT((sc)->tx_map_unused_get_cnt, TSEC_TX_NUM_DESC); \ 138 TSEC_CNT_INIT((sc)->tx_map_unused_put_cnt, TSEC_TX_NUM_DESC); \ 139 TSEC_CNT_INIT((sc)->tx_map_used_get_cnt, TSEC_TX_NUM_DESC); \ 140 TSEC_CNT_INIT((sc)->tx_map_used_put_cnt, TSEC_TX_NUM_DESC); \ 141 } while (0) 142 143 /* interface to get/put unused TX maps */ 144 #define TSEC_ALLOC_TX_MAP(sc) \ 145 TSEC_GET_GENERIC(sc, tx_map_unused_data, tx_map_unused_get_cnt, \ 146 TSEC_TX_NUM_DESC) 147 148 #define TSEC_FREE_TX_MAP(sc, val) \ 149 TSEC_PUT_GENERIC(sc, tx_map_unused_data, tx_map_unused_put_cnt, \ 150 TSEC_TX_NUM_DESC, val) 151 152 /* interface to get/put used TX maps */ 153 #define TSEC_GET_TX_MAP(sc) \ 154 TSEC_GET_GENERIC(sc, tx_map_used_data, tx_map_used_get_cnt, \ 155 TSEC_TX_NUM_DESC) 156 157 #define TSEC_PUT_TX_MAP(sc, val) \ 158 TSEC_PUT_GENERIC(sc, tx_map_used_data, tx_map_used_put_cnt, \ 159 TSEC_TX_NUM_DESC, val) 160 161 /* interface to get/put TX mbufs in send queue */ 162 #define TSEC_TX_MBUF_CNT_INIT(sc) do { \ 163 TSEC_CNT_INIT((sc)->tx_mbuf_used_get_cnt, TSEC_TX_NUM_DESC); \ 164 TSEC_CNT_INIT((sc)->tx_mbuf_used_put_cnt, TSEC_TX_NUM_DESC); \ 165 } while (0) 166 167 #define TSEC_GET_TX_MBUF(sc) \ 168 TSEC_GET_GENERIC(sc, tx_mbuf_used_data, tx_mbuf_used_get_cnt, \ 169 TSEC_TX_NUM_DESC) 170 171 #define TSEC_PUT_TX_MBUF(sc, val) \ 172 TSEC_PUT_GENERIC(sc, tx_mbuf_used_data, tx_mbuf_used_put_cnt, \ 173 TSEC_TX_NUM_DESC, val) 174 175 #define TSEC_EMPTYQ_TX_MBUF(sc) \ 176 ((sc)->tx_mbuf_used_get_cnt == (sc)->tx_mbuf_used_put_cnt) 177 178 /* interface for manage tx tsec_desc */ 179 #define TSEC_TX_DESC_CNT_INIT(sc) do { \ 180 TSEC_CNT_INIT((sc)->tx_cur_desc_cnt, TSEC_TX_NUM_DESC); \ 181 TSEC_CNT_INIT((sc)->tx_dirty_desc_cnt, TSEC_TX_NUM_DESC); \ 182 } while (0) 183 184 #define TSEC_GET_CUR_TX_DESC(sc) \ 185 &TSEC_GET_GENERIC(sc, tsec_tx_vaddr, tx_cur_desc_cnt, \ 186 TSEC_TX_NUM_DESC) 187 188 #define TSEC_GET_DIRTY_TX_DESC(sc) \ 189 &TSEC_GET_GENERIC(sc, tsec_tx_vaddr, tx_dirty_desc_cnt, \ 190 TSEC_TX_NUM_DESC) 191 192 #define TSEC_BACK_DIRTY_TX_DESC(sc) \ 193 TSEC_BACK_GENERIC(sc, tx_dirty_desc_cnt, TSEC_TX_NUM_DESC) 194 195 #define TSEC_CUR_DIFF_DIRTY_TX_DESC(sc) \ 196 ((sc)->tx_cur_desc_cnt != (sc)->tx_dirty_desc_cnt) 197 198 #define TSEC_FREE_TX_DESC(sc) \ 199 (((sc)->tx_cur_desc_cnt < (sc)->tx_dirty_desc_cnt) ? \ 200 ((sc)->tx_dirty_desc_cnt - (sc)->tx_cur_desc_cnt - 1) \ 201 : \ 202 (TSEC_TX_NUM_DESC - (sc)->tx_cur_desc_cnt \ 203 + (sc)->tx_dirty_desc_cnt - 1)) 204 205 /* interface for manage rx tsec_desc */ 206 #define TSEC_RX_DESC_CNT_INIT(sc) do { \ 207 TSEC_CNT_INIT((sc)->rx_cur_desc_cnt, TSEC_RX_NUM_DESC); \ 208 } while (0) 209 210 #define TSEC_GET_CUR_RX_DESC(sc) \ 211 &TSEC_GET_GENERIC(sc, tsec_rx_vaddr, rx_cur_desc_cnt, \ 212 TSEC_RX_NUM_DESC) 213 214 #define TSEC_BACK_CUR_RX_DESC(sc) \ 215 TSEC_BACK_GENERIC(sc, rx_cur_desc_cnt, TSEC_RX_NUM_DESC) 216 217 #define TSEC_GET_CUR_RX_DESC_CNT(sc) \ 218 ((sc)->rx_cur_desc_cnt) 219 220 /* init all counters (for init only!) */ 221 #define TSEC_TX_RX_COUNTERS_INIT(sc) do { \ 222 TSEC_TX_MAP_CNT_INIT(sc); \ 223 TSEC_TX_MBUF_CNT_INIT(sc); \ 224 TSEC_TX_DESC_CNT_INIT(sc); \ 225 TSEC_RX_DESC_CNT_INIT(sc); \ 226 } while (0) 227 228 /* read/write bus functions */ 229 #define TSEC_READ(sc, reg) \ 230 bus_space_read_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg)) 231 #define TSEC_WRITE(sc, reg, val) \ 232 bus_space_write_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg), (val)) 233 234 /* Lock for transmitter */ 235 #define TSEC_TRANSMIT_LOCK(sc) do { \ 236 mtx_assert(&(sc)->receive_lock, MA_NOTOWNED); \ 237 mtx_lock(&(sc)->transmit_lock); \ 238 } while (0) 239 240 #define TSEC_TRANSMIT_UNLOCK(sc) mtx_unlock(&(sc)->transmit_lock) 241 #define TSEC_TRANSMIT_LOCK_ASSERT(sc) mtx_assert(&(sc)->transmit_lock, MA_OWNED) 242 243 /* Lock for receiver */ 244 #define TSEC_RECEIVE_LOCK(sc) do { \ 245 mtx_assert(&(sc)->transmit_lock, MA_NOTOWNED); \ 246 mtx_lock(&(sc)->receive_lock); \ 247 } while (0) 248 249 #define TSEC_RECEIVE_UNLOCK(sc) mtx_unlock(&(sc)->receive_lock) 250 #define TSEC_RECEIVE_LOCK_ASSERT(sc) mtx_assert(&(sc)->receive_lock, MA_OWNED) 251 252 /* Global tsec lock (with all locks) */ 253 #define TSEC_GLOBAL_LOCK(sc) do { \ 254 if ((mtx_owned(&(sc)->transmit_lock) ? 1 : 0) != \ 255 (mtx_owned(&(sc)->receive_lock) ? 1 : 0)) { \ 256 panic("tsec deadlock possibility detection!"); \ 257 } \ 258 mtx_lock(&(sc)->transmit_lock); \ 259 mtx_lock(&(sc)->receive_lock); \ 260 } while (0) 261 262 #define TSEC_GLOBAL_UNLOCK(sc) do { \ 263 TSEC_RECEIVE_UNLOCK(sc); \ 264 TSEC_TRANSMIT_UNLOCK(sc); \ 265 } while (0) 266 267 #define TSEC_GLOBAL_LOCK_ASSERT(sc) do { \ 268 TSEC_TRANSMIT_LOCK_ASSERT(sc); \ 269 TSEC_RECEIVE_LOCK_ASSERT(sc); \ 270 } while (0) 271 272 /* From global to {transmit,receive} */ 273 #define TSEC_GLOBAL_TO_TRANSMIT_LOCK(sc) do { \ 274 mtx_unlock(&(sc)->receive_lock);\ 275 } while (0) 276 277 #define TSEC_GLOBAL_TO_RECEIVE_LOCK(sc) do { \ 278 mtx_unlock(&(sc)->transmit_lock);\ 279 } while (0) 280 281 struct tsec_desc { 282 volatile uint16_t flags; /* descriptor flags */ 283 volatile uint16_t length; /* buffer length */ 284 volatile uint32_t bufptr; /* buffer pointer */ 285 }; 286 287 #define TSEC_READ_RETRY 10000 288 #define TSEC_READ_DELAY 100 289