1 /* $NetBSD: usbnet.h,v 1.6 2019/08/07 07:25:50 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Matthew R. Green 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 * 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. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #ifndef _DEV_USB_USBNET_H 32 #define _DEV_USB_USBNET_H 33 34 /* 35 * Common code/data shared by all USB ethernet drivers (using these routines.) 36 * 37 * This framework provides the following features for USB ethernet drivers: 38 * 39 * - USB endpoint pipe handling 40 * - rx and tx chain handling 41 * - generic handlers or support for several struct ifnet callbacks 42 * - MII bus locking 43 * - interrupt handling 44 * - partial autoconf handling 45 * 46 * Consumers of this interface need to: 47 * 48 * - replace most softc members with "struct usbnet" usage, in particular 49 * use usbnet pointer for ifp->if_softc, and device_private (real softc 50 * can be stored in un_sc member) 51 * - use MII bus lock / access methods 52 * - usbnet_attach() to initialise and allocate rx/tx chains 53 * - usbnet_attach_ifp() to attach the interface, and either ether_ifattach() 54 * for ethernet devices, or if_alloc_sadl()/bpf_attach() pair otherwise. 55 * - usbnet_detach() to clean them up 56 * - usbnet_activate() for autoconf 57 * - interface ioctl and start have direct frontends with callbacks for 58 * device specific handling: 59 * - ioctl can use either a device-specific override (useful for special 60 * cases), but provides a normal handler with callback to handle 61 * ENETRESET conditions that should be sufficient for most users 62 * - start uses usbnet send callback 63 * - interface init and stop have helper functions 64 * - device specific init should use usbnet_init_rx_tx() to open pipes 65 * to the device and setup the rx/tx chains for use after any device 66 * specific setup 67 * - usbnet_stop() must be called with the un_lock held, and will 68 * call the device-specific usbnet stop callback, which enables the 69 * standard init calls stop idiom. 70 * - interrupt handling: 71 * - for rx, usbnet_init_rx_tx() will enable the receive pipes and 72 * call the rx_loop callback to handle device specific processing of 73 * packets, which can use usbnet_enqueue() to provide data to the 74 * higher layers 75 * - for tx, usbnet_start (if_start) will pull entries out of the 76 * transmit queue and use the send callback for the given mbuf. 77 * the usb callback will use usbnet_txeof() for the transmit 78 * completion function (internal to usbnet) 79 */ 80 81 #include <sys/device.h> 82 #include <sys/mbuf.h> 83 #include <sys/rndsource.h> 84 #include <sys/mutex.h> 85 86 #include <net/bpf.h> 87 #include <net/if.h> 88 #include <net/if_arp.h> 89 #include <net/if_dl.h> 90 #include <net/if_ether.h> 91 #include <net/if_media.h> 92 93 #include <dev/mii/mii.h> 94 #include <dev/mii/miivar.h> 95 96 #include <dev/usb/usb.h> 97 #include <dev/usb/usbdi.h> 98 #include <dev/usb/usbdivar.h> 99 #include <dev/usb/usbdi_util.h> 100 #include <dev/usb/usbdevs.h> 101 102 /* 103 * Per-transfer data, initialised in usbnet_[rt]x_list_init(). 104 * 105 * Front-end must set uncd_tx_list_cnt and uncd_rx_list_cnt before calling 106 * list init, which will allocate the chain arrays, and must be NULL to 107 * indicate the first call. 108 */ 109 struct usbnet; 110 struct usbnet_chain { 111 struct usbnet *unc_un; 112 struct usbd_xfer *unc_xfer; 113 uint8_t *unc_buf; 114 }; 115 116 struct usbnet_cdata { 117 struct usbnet_chain *uncd_tx_chain; 118 struct usbnet_chain *uncd_rx_chain; 119 120 unsigned uncd_rx_bufsz; 121 unsigned uncd_tx_bufsz; 122 unsigned uncd_rx_list_cnt; 123 unsigned uncd_tx_list_cnt; 124 125 int uncd_tx_prod; 126 int uncd_tx_cnt; 127 int uncd_rx_cnt; 128 }; 129 130 /* 131 * Extend this as necessary. axe(4) claims to want 6 total, but 132 * does not implement them. 133 */ 134 enum usbnet_ep { 135 USBNET_ENDPT_RX, 136 USBNET_ENDPT_TX, 137 USBNET_ENDPT_INTR, 138 USBNET_ENDPT_MAX, 139 }; 140 141 /* Interface stop callback. */ 142 typedef void (*usbnet_stop_cb)(struct ifnet *, int); 143 /* Interface ioctl callback. */ 144 typedef int (*usbnet_ioctl_cb)(struct ifnet *, u_long, void *); 145 /* Initialise device callback. */ 146 typedef int (*usbnet_init_cb)(struct ifnet *); 147 148 /* MII read register callback. */ 149 typedef usbd_status (*usbnet_mii_read_reg_cb)(struct usbnet *, int reg, 150 int phy, uint16_t *val); 151 /* MII write register callback. */ 152 typedef usbd_status (*usbnet_mii_write_reg_cb)(struct usbnet *, int reg, 153 int phy, uint16_t val); 154 /* MII status change callback. */ 155 typedef void (*usbnet_mii_statchg_cb)(struct ifnet *); 156 157 /* Prepare packet to send callback, returns length. */ 158 typedef unsigned (*usbnet_tx_prepare_cb)(struct usbnet *, struct mbuf *, 159 struct usbnet_chain *); 160 /* Receive some packets callback. */ 161 typedef void (*usbnet_rx_loop_cb)(struct usbnet *, struct usbd_xfer *, 162 struct usbnet_chain *, uint32_t); 163 /* Interrupt pipe callback. */ 164 typedef void (*usbnet_intr_cb)(struct usbnet *, usbd_status); 165 166 /* 167 * Generic USB ethernet structure. Use this as ifp->if_softc and 168 * set as device_private() in attach. 169 * 170 * Devices without MII should call usbnet_attach_ifp() with have_mii set 171 * to true, and should ensure that the un_statchg_cb callback sets the 172 * un_link member. Devices without MII have this forced to true. 173 */ 174 struct usbnet { 175 void *un_sc; /* real softc */ 176 device_t un_dev; 177 struct usbd_interface *un_iface; 178 struct usbd_device * un_udev; 179 krndsource_t un_rndsrc; 180 181 struct ethercom un_ec; 182 struct mii_data un_mii; 183 int un_phyno; 184 uint8_t un_eaddr[ETHER_ADDR_LEN]; 185 186 enum usbnet_ep un_ed[USBNET_ENDPT_MAX]; 187 struct usbd_pipe *un_ep[USBNET_ENDPT_MAX]; 188 189 struct usbnet_cdata un_cdata; 190 struct callout un_stat_ch; 191 int un_if_flags; 192 193 /* 194 * - un_lock protects most of the structure 195 * - un_miilock must be held to access this device's MII bus 196 * - un_rxlock protects the rx path and its data 197 * - un_txlock protects the tx path and its data 198 * - un_detachcv handles detach vs open references 199 */ 200 kmutex_t un_lock; 201 kmutex_t un_miilock; 202 kmutex_t un_rxlock; 203 kmutex_t un_txlock; 204 kcondvar_t un_detachcv; 205 206 struct usb_task un_ticktask; 207 208 int un_refcnt; 209 int un_timer; 210 211 bool un_dying; 212 bool un_stopping; 213 bool un_link; 214 bool un_attached; 215 216 struct timeval un_rx_notice; 217 struct timeval un_tx_notice; 218 struct timeval un_intr_notice; 219 220 usbnet_stop_cb un_stop_cb; 221 usbnet_ioctl_cb un_ioctl_cb; 222 usbnet_ioctl_cb un_override_ioctl_cb; 223 usbnet_init_cb un_init_cb; 224 usbnet_mii_read_reg_cb un_read_reg_cb; 225 usbnet_mii_write_reg_cb un_write_reg_cb; 226 usbnet_mii_statchg_cb un_statchg_cb; 227 usbnet_tx_prepare_cb un_tx_prepare_cb; 228 usbnet_rx_loop_cb un_rx_loop_cb; 229 usbnet_intr_cb un_intr_cb; 230 231 /* Passed to usbd_setup_xfer(). */ 232 int un_rx_xfer_flags; 233 int un_tx_xfer_flags; 234 235 /* 236 * if un_intr_buf is not NULL, use usbd_open_pipe_intr() not 237 * usbd_open_pipe() for USBNET_ENDPT_INTR, with this buffer, 238 * size, and interval. 239 */ 240 void *un_intr_buf; 241 unsigned un_intr_bufsz; 242 unsigned un_intr_interval; 243 }; 244 245 #define usbnet_ifp(un) (&(un)->un_ec.ec_if) 246 #define usbnet_mii(un) (un->un_ec.ec_mii) 247 #define usbnet_ec(un) (&(un)->un_ec) 248 #define usbnet_softc(un) (un->un_sc) 249 250 /* 251 * Endpoint / rx/tx chain management: 252 * 253 * usbnet_attach() allocates rx and tx chains 254 * usbnet_init_rx_tx() open pipes, initialises the rx/tx chains for use 255 * usbnet_stop() stops pipes, cleans (not frees) rx/tx chains, locked 256 * version assumes un_lock is held 257 * usbnet_detach() frees the rx/tx chains 258 * 259 * Setup un_ed[] with valid end points before calling usbnet_init_rx_tx(). 260 * Will return with un_ep[] initialised upon success. 261 */ 262 int usbnet_init_rx_tx(struct usbnet * const, unsigned, unsigned); 263 264 /* locking */ 265 static __inline__ void 266 usbnet_lock(struct usbnet *un) 267 { 268 mutex_enter(&un->un_lock); 269 } 270 271 static __inline__ void 272 usbnet_unlock(struct usbnet *un) 273 { 274 mutex_exit(&un->un_lock); 275 } 276 277 static __inline__ void 278 usbnet_isowned(struct usbnet *un) 279 { 280 KASSERT(mutex_owned(&un->un_lock)); 281 } 282 283 static __inline__ void 284 usbnet_lock_rx(struct usbnet *un) 285 { 286 mutex_enter(&un->un_rxlock); 287 } 288 289 static __inline__ void 290 usbnet_unlock_rx(struct usbnet *un) 291 { 292 mutex_exit(&un->un_rxlock); 293 } 294 295 static __inline__ void 296 usbnet_isowned_rx(struct usbnet *un) 297 { 298 KASSERT(mutex_owned(&un->un_rxlock)); 299 } 300 301 static __inline__ void 302 usbnet_lock_tx(struct usbnet *un) 303 { 304 mutex_enter(&un->un_txlock); 305 } 306 307 static __inline__ void 308 usbnet_unlock_tx(struct usbnet *un) 309 { 310 mutex_exit(&un->un_txlock); 311 } 312 313 static __inline__ void 314 usbnet_isowned_tx(struct usbnet *un) 315 { 316 KASSERT(mutex_owned(&un->un_txlock)); 317 } 318 319 /* mii */ 320 void usbnet_lock_mii(struct usbnet *); 321 void usbnet_lock_mii_un_locked(struct usbnet *); 322 void usbnet_unlock_mii(struct usbnet *); 323 void usbnet_unlock_mii_un_locked(struct usbnet *); 324 325 static __inline__ void 326 usbnet_isowned_mii(struct usbnet *un) 327 { 328 KASSERT(mutex_owned(&un->un_miilock)); 329 } 330 331 int usbnet_miibus_readreg(device_t, int, int, uint16_t *); 332 int usbnet_miibus_writereg(device_t, int, int, uint16_t); 333 void usbnet_miibus_statchg(struct ifnet *); 334 335 /* interrupt handling */ 336 void usbnet_enqueue(struct usbnet * const, uint8_t *, size_t, int, 337 uint32_t, int); 338 void usbnet_input(struct usbnet * const, uint8_t *, size_t); 339 340 /* autoconf */ 341 void usbnet_attach(struct usbnet *un, const char *, unsigned, unsigned); 342 void usbnet_attach_ifp(struct usbnet *, bool, unsigned, unsigned, int); 343 int usbnet_detach(device_t, int); 344 int usbnet_activate(device_t, devact_t); 345 346 /* stop backend */ 347 void usbnet_stop(struct usbnet *, struct ifnet *, int); 348 void usbnet_stop_locked(struct usbnet *, struct ifnet *, int); 349 350 #endif /* _DEV_USB_USBNET_H */ 351