1 /* $NetBSD: if_ze.c,v 1.12 2002/05/27 16:54:18 ragge Exp $ */ 2 /* 3 * Copyright (c) 1998 James R. Maynard III. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by James R. Maynard III. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Standalone routine for the SGEC Ethernet controller. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/queue.h> 37 38 #include <net/if.h> 39 #include <net/if_ether.h> 40 41 #include <netinet/in.h> 42 #include <netinet/in_systm.h> 43 44 #include <lib/libsa/netif.h> 45 #include <lib/libsa/stand.h> 46 #include <lib/libsa/net.h> 47 48 #include "lib/libkern/libkern.h" 49 50 #include <dev/ic/sgecreg.h> 51 52 #include "arch/vax/include/sid.h" 53 #include "arch/vax/include/rpb.h" 54 55 #include "vaxstand.h" 56 57 static int ze_get(struct iodesc *, void *, size_t, time_t); 58 static int ze_put(struct iodesc *, void *, size_t); 59 60 61 struct netif_driver ze_driver = { 62 0, 0, 0, 0, ze_get, ze_put, 63 }; 64 65 #define NRCV 8 /* allocate 8 receive descriptors */ 66 #define NXMT 4 /* and 4 transmit - must be >1 */ 67 #define SETUP_FRAME_LEN 128 /* length of the setup frame */ 68 69 /* allocate a buffer on an octaword boundary */ 70 #define OW_ALLOC(x) ((void *)((int)((int)alloc((x) + 15) + 15) & ~15)) 71 72 static volatile struct zedevice *addr; 73 74 struct ze_tdes *ze_tdes_list; /* transmit desc list */ 75 struct ze_rdes *ze_rdes_list; /* and receive desc list */ 76 u_char ze_myaddr[ETHER_ADDR_LEN]; /* my Ethernet address */ 77 78 int 79 zeopen(struct open_file *f, int adapt, int ctlr, int unit, int part) 80 { 81 u_long nicsr0_work, *nisa_rom; 82 struct ze_tdes *ze_setup_tdes_list; 83 int i; 84 85 /* point to the device in memory */ 86 if (askname == 0) /* Override if autoboot */ 87 addr = (struct zedevice *)bootrpb.csrphy; 88 else 89 addr = (struct zedevice *)0x20008000; 90 91 /* reset the device and wait for completion */ 92 addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE; 93 while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0) 94 ; 95 if (addr->ze_nicsr5 & ZE_NICSR5_SF) { 96 printf("SGEC self-test failed...\n"); 97 return 1; 98 } 99 100 /* Get our Ethernet address */ 101 if (vax_boardtype == VAX_BTYP_49) { 102 nisa_rom = (u_long *)0x27800000; 103 for (i=0; i<ETHER_ADDR_LEN; i++) 104 ze_myaddr[i] = nisa_rom[i] & 0377; 105 } else if (vax_boardtype == VAX_BTYP_VXT) { 106 nisa_rom = (u_long *)0x200c4000; 107 for (i=0; i<ETHER_ADDR_LEN; i++) 108 ze_myaddr[i] = nisa_rom[i] & 0xff; 109 } else { 110 nisa_rom = (u_long *)0x20084000; 111 for (i=0; i<ETHER_ADDR_LEN; i++) 112 if (vax_boardtype == VAX_BTYP_660) 113 ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24; 114 else 115 ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8; 116 } 117 printf("SGEC: Ethernet address %s\n", ether_sprintf(ze_myaddr)); 118 119 /* initialize SGEC operating mode */ 120 /* disable interrupts here */ 121 nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO | 122 (ZE_NICSR0_IV_MASK & 0x0108); 123 while (addr->ze_nicsr0 != nicsr0_work) 124 addr->ze_nicsr0 = nicsr0_work; 125 if (addr->ze_nicsr5 & ZE_NICSR5_ME) 126 addr->ze_nicsr5 |= ZE_NICSR5_ME; 127 /* reenable interrupts here */ 128 129 /* Allocate space for descriptor lists and buffers, 130 then initialize them. Set up both lists as a ring. */ 131 ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes)); 132 ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes)); 133 for (i=0; i < NRCV; i++) { 134 bzero(ze_rdes_list+i,sizeof(struct ze_rdes)); 135 ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW; 136 ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN; 137 ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN); 138 } 139 bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes)); 140 ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW; 141 ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA; 142 ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list; 143 for (i=0; i < NXMT; i++) { 144 bzero(ze_tdes_list+i,sizeof(struct ze_tdes)); 145 ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS; 146 ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN; 147 ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN); 148 } 149 bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes)); 150 ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA; 151 ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW; 152 ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list; 153 154 /* Build setup frame. We set the SGEC to do a 155 perfect filter on our own address. */ 156 ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes)); 157 bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes)); 158 ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW; 159 ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP; 160 ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN; 161 ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN); 162 bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN); 163 for (i=0; i < 16; i++) 164 bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i), 165 ETHER_ADDR_LEN); 166 ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA; 167 ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list; 168 169 /* Start the transmitter and initialize almost everything else. */ 170 addr->ze_nicsr4 = ze_setup_tdes_list; 171 addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST | 172 ZE_NICSR6_DC | ZE_NICSR6_BL_4; 173 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP) 174 ; /* wait for the frame to be processed */ 175 176 /* Setup frame is done processing, initialize the receiver and 177 point the transmitter to the real tdes list. */ 178 addr->ze_nicsr4 = ze_tdes_list; 179 addr->ze_nicsr3 = ze_rdes_list; 180 addr->ze_nicsr6 |= ZE_NICSR6_SR; 181 182 /* And away-y-y we go! */ 183 184 net_devinit(f, &ze_driver, ze_myaddr); 185 return 0; 186 } 187 188 int 189 ze_get(desc, pkt, maxlen, timeout) 190 struct iodesc *desc; 191 void *pkt; 192 size_t maxlen; 193 time_t timeout; 194 { 195 int timeout_ctr=100000*timeout, len, rdes; 196 197 while (timeout_ctr-- > 0) { 198 199 /* If there's not a packet waiting for us, just decrement the 200 timeout counter. */ 201 if (!(addr->ze_nicsr5 & ZE_NICSR5_RI)) 202 continue; 203 204 /* Look through the receive descriptor list for the packet. */ 205 for (rdes=0; rdes<NRCV; rdes++) { 206 if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW) 207 continue; 208 209 /* If the packet has an error, ignore it. */ 210 if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES) 211 len = 0; 212 213 /* Copy the packet, up to the length supplied by the caller, to 214 the caller's buffer. */ 215 else { 216 if ((len = (ze_rdes_list[rdes].ze_framelen & 217 (~ ZE_FRAMELEN_OW))) > maxlen) 218 len = maxlen; 219 bcopy((void *)ze_rdes_list[rdes].ze_bufaddr, 220 pkt,len); 221 } 222 223 /* Give ownership of this descriptor back to the SGEC. */ 224 ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW; 225 226 /* If we actually got a good packet, reset the error flags and 227 tell the SGEC to look for more before returning. */ 228 if (len > 0) { 229 addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | 230 ZE_NICSR5_IS; 231 addr->ze_nicsr2=ZE_NICSR2_RXPD; 232 return len; 233 } 234 } 235 } 236 237 /* If we're going to return an error indication, at least reset the 238 error flags and tell the SGEC to keep receiving first. */ 239 addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS; 240 addr->ze_nicsr2=ZE_NICSR2_RXPD; 241 return 0; 242 } 243 244 int 245 ze_put(desc, pkt, len) 246 struct iodesc *desc; 247 void *pkt; 248 size_t len; 249 { 250 int timeout=100000; 251 252 /* The SGEC maintains its position in the transmit descriptor list 253 for the next frame to transmit. Unfortunately, there's no way to tell 254 from software just where that is. We're forced to reset the position 255 whenever we send a frame, which requires waiting for the previous 256 frame to be sent. Argh. */ 257 while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN) 258 ; 259 260 /* Copy the packet to the buffer we allocated. */ 261 bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len); 262 263 /* Set the packet length in the descriptor, increasing it to the 264 minimum size if needed. */ 265 ze_tdes_list[0].ze_bufsize = len; 266 if (len < ETHER_MIN_LEN) 267 ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN; 268 269 /* Give ownership of the descriptor to the SGEC and tell it to start 270 transmitting. */ 271 ze_tdes_list[0].ze_tdr = ZE_TDR_OW; 272 addr->ze_nicsr4 = ze_tdes_list; 273 addr->ze_nicsr1 = ZE_NICSR1_TXPD; 274 275 /* Wait for the frame to be sent, but not too long. */ 276 timeout = 100000; 277 while (((addr->ze_nicsr5 & ZE_NICSR5_TI) == 0) && (--timeout>0)) 278 ; 279 280 /* Reset the transmitter interrupt pending flag. */ 281 addr->ze_nicsr5 |= ZE_NICSR5_TI; 282 283 /* Return good if we didn't timeout, or error if we did. */ 284 if (timeout>0) return len; 285 return -1; 286 } 287 288 int 289 zeclose(struct open_file *f) 290 { 291 addr->ze_nicsr6 = ZE_NICSR6_RE; 292 293 return 0; 294 } 295