1 /* $NetBSD: sip.c,v 1.2 2011/01/27 17:38:04 phx Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 34 #include <netinet/in.h> 35 #include <netinet/in_systm.h> 36 37 #include <lib/libsa/stand.h> 38 #include <lib/libsa/net.h> 39 40 #include "globals.h" 41 42 /* 43 * - reverse endian access every CSR. 44 * - no VTOPHYS() translation, vaddr_t == paddr_t. 45 * - PIPT writeback cache aware. 46 */ 47 #define CSR_READ(l, r) in32rb((l)->csr+(r)) 48 #define CSR_WRITE(l, r, v) out32rb((l)->csr+(r), (v)) 49 #define VTOPHYS(va) (uint32_t)(va) 50 #define DEVTOV(pa) (uint32_t)(pa) 51 #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz)) 52 #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz)) 53 #define DELAY(n) delay(n) 54 #define ALLOC(T,A) (T *)allocaligned(sizeof(T),(A)) 55 56 struct desc { 57 uint32_t xd0, xd1, xd2; 58 uint32_t hole; 59 }; 60 #define XD1_OWN (1U << 31) 61 #define XD1_OK (1U << 27) 62 63 #define SIP_CR 0x00 64 #define CR_RST (1U << 8) /* software reset */ 65 #define CR_RXR (1U << 5) /* Rx abort and reset */ 66 #define CR_TXR (1U << 4) /* Tx abort and reset */ 67 #define CR_RXD (1U << 3) /* graceful Rx stop */ 68 #define CR_RXE (1U << 2) /* run and activate Rx */ 69 #define CR_TXD (1U << 1) /* graceful Tx stop */ 70 #define CR_TXE (1U << 0) /* run and activate Tx */ 71 #define SIP_CFG 0x04 72 #define SIP_MEAR 0x08 73 #define MEAR_EESEL (1U << 3) /* SEEP chipselect */ 74 #define MEAR_EECLK (1U << 2) /* clock */ 75 #define MEAR_EEDO (1U << 1) /* bit retrieve */ 76 #define MEAR_EEDI (1U << 0) /* bit feed */ 77 #define SIP_IMR 0x14 78 #define SIP_IER 0x18 79 #define SIP_TXDP 0x20 80 #define SIP_TXCFG 0x24 81 #define TXCFG_CSI (1U << 31) 82 #define TXCFG_HBI (1U << 30) 83 #define TXCFG_ATP (1U << 28) 84 #define TXCFG_DMA256 0x300000 85 #define SIP_RXDP 0x30 86 #define SIP_RXCFG 0x34 87 #define RXCFG_ATX (1U << 28) 88 #define RXCFG_DMA256 0x300000 89 #define SIP_RFCR 0x48 90 #define RFCR_RFEN (1U << 31) /* activate Rx filter */ 91 #define RFCR_APM (1U << 27) /* accept perfect match */ 92 #define SIP_RFDR 0x4c 93 #define SIP_MIBC 0x5c 94 #define SIP_BMCR 0x80 95 #define SIP_PHYSTS 0xc0 96 #define SIP_PHYCR 0xe4 97 98 #define FRAMESIZE 1536 99 100 struct local { 101 struct desc txd[2]; 102 struct desc rxd[2]; 103 uint8_t store[2][FRAMESIZE]; 104 unsigned csr, tx, rx; 105 unsigned phy, bmsr, anlpar; 106 unsigned cr; 107 }; 108 109 static int read_eeprom(struct local *, int); 110 static unsigned mii_read(struct local *, int, int); 111 static void mii_write(struct local *, int, int, int); 112 static void mii_initphy(struct local *); 113 static void mii_dealan(struct local *, unsigned); 114 115 /* Table and macro to bit-reverse an octet. */ 116 static const uint8_t bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; 117 #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf]) 118 119 int 120 sip_match(unsigned tag, void *data) 121 { 122 unsigned v; 123 124 v = pcicfgread(tag, PCI_ID_REG); 125 switch (v) { 126 case PCI_DEVICE(0x100b, 0x0020): 127 return 1; 128 } 129 return 0; 130 } 131 132 void * 133 sip_init(unsigned tag, void *data) 134 { 135 unsigned val, i, fdx, txc, rxc; 136 struct local *l; 137 struct desc *txd, *rxd; 138 uint16_t eedata[4], *ee; 139 uint8_t *en; 140 141 val = pcicfgread(tag, PCI_ID_REG); 142 if (PCI_DEVICE(0x100b, 0x0020) != val) 143 return NULL; 144 145 l = ALLOC(struct local, 32); /* desc alignment */ 146 memset(l, 0, sizeof(struct local)); 147 l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */ 148 149 CSR_WRITE(l, SIP_IER, 0); 150 CSR_WRITE(l, SIP_IMR, 0); 151 CSR_WRITE(l, SIP_RFCR, 0); 152 CSR_WRITE(l, SIP_CR, CR_RST); 153 do { 154 val = CSR_READ(l, SIP_CR); 155 } while (val & CR_RST); /* S1C */ 156 157 mii_initphy(l); 158 159 ee = eedata; en = data; 160 ee[0] = read_eeprom(l, 6); 161 ee[1] = read_eeprom(l, 7); 162 ee[2] = read_eeprom(l, 8); 163 ee[3] = read_eeprom(l, 9); 164 en[0] = ((*ee & 0x1) << 7); 165 ee++; 166 en[0] |= ((*ee & 0xFE00) >> 9); 167 en[1] = ((*ee & 0x1FE) >> 1); 168 en[2] = ((*ee & 0x1) << 7); 169 ee++; 170 en[2] |= ((*ee & 0xFE00) >> 9); 171 en[3] = ((*ee & 0x1FE) >> 1); 172 en[4] = ((*ee & 0x1) << 7); 173 ee++; 174 en[4] |= ((*ee & 0xFE00) >> 9); 175 en[5] = ((*ee & 0x1FE) >> 1); 176 for (i = 0; i < 6; i++) 177 en[i] = bbr(en[i]); 178 179 printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x, ", 180 en[0], en[1], en[2], en[3], en[4], en[5]); 181 DPRINTF(("PHY %d (%04x.%04x)\n", l->phy, 182 mii_read(l, l->phy, 2), mii_read(l, l->phy, 3))); 183 184 mii_dealan(l, 5); 185 186 /* speed and duplexity are found in CFG */ 187 val = CSR_READ(l, SIP_CFG); 188 fdx = !!(val & (1U << 29)); 189 printf("%s", (val & (1U << 30)) ? "100Mbps" : "10Mbps"); 190 if (fdx) 191 printf("-FDX"); 192 printf("\n"); 193 194 txd = &l->txd[0]; 195 txd->xd0 = htole32(VTOPHYS(txd)); 196 rxd = l->rxd; 197 rxd[0].xd0 = htole32(VTOPHYS(&rxd[1])); 198 rxd[0].xd1 = htole32(XD1_OWN | FRAMESIZE); 199 rxd[0].xd2 = htole32(VTOPHYS(l->store[0])); 200 rxd[1].xd0 = htole32(VTOPHYS(&rxd[0])); 201 rxd[1].xd1 = htole32(XD1_OWN | FRAMESIZE); 202 rxd[1].xd2 = htole32(VTOPHYS(l->store[1])); 203 wbinv(l, sizeof(struct local)); 204 l->tx = l->rx = 0; 205 206 CSR_WRITE(l, SIP_RFCR, 0); 207 CSR_WRITE(l, SIP_RFDR, (en[1] << 8) | en[0]); 208 CSR_WRITE(l, SIP_RFCR, 2); 209 CSR_WRITE(l, SIP_RFDR, (en[3] << 8) | en[2]); 210 CSR_WRITE(l, SIP_RFCR, 4); 211 CSR_WRITE(l, SIP_RFDR, (en[5] << 8) | en[4]); 212 CSR_WRITE(l, SIP_RFCR, RFCR_RFEN | RFCR_APM); 213 214 txc = TXCFG_ATP | TXCFG_DMA256 | 0x1002; 215 rxc = RXCFG_DMA256 | 0x20; 216 if (fdx) { 217 txc |= TXCFG_CSI | TXCFG_HBI; 218 rxc |= RXCFG_ATX; 219 } 220 l->cr = CR_RXE; 221 CSR_WRITE(l, SIP_TXDP, VTOPHYS(txd)); 222 CSR_WRITE(l, SIP_RXDP, VTOPHYS(rxd)); 223 CSR_WRITE(l, SIP_TXCFG, txc); 224 CSR_WRITE(l, SIP_RXCFG, rxc); 225 CSR_WRITE(l, SIP_CR, l->cr); 226 227 return l; 228 } 229 230 int 231 sip_send(void *dev, char *buf, unsigned len) 232 { 233 struct local *l = dev; 234 volatile struct desc *txd; 235 unsigned loop; 236 237 wbinv(buf, len); 238 txd = &l->txd[l->tx]; 239 txd->xd2 = htole32(VTOPHYS(buf)); 240 txd->xd1 = htole32(XD1_OWN | (len & 0xfff)); 241 wbinv(txd, sizeof(struct desc)); 242 CSR_WRITE(l, SIP_CR, l->cr | CR_TXE); 243 loop = 100; 244 do { 245 if ((le32toh(txd->xd1) & XD1_OWN) == 0) 246 goto done; 247 DELAY(10); 248 inv(txd, sizeof(struct desc)); 249 } while (--loop != 0); 250 printf("xmit failed\n"); 251 return -1; 252 done: 253 l->tx ^= 1; 254 return len; 255 } 256 257 int 258 sip_recv(void *dev, char *buf, unsigned maxlen, unsigned timo) 259 { 260 struct local *l = dev; 261 volatile struct desc *rxd; 262 unsigned bound, rxstat, len; 263 uint8_t *ptr; 264 265 bound = 1000 * timo; 266 printf("recving with %u sec. timeout\n", timo); 267 again: 268 rxd = &l->rxd[l->rx]; 269 do { 270 inv(rxd, sizeof(struct desc)); 271 rxstat = le32toh(rxd->xd1); 272 if ((rxstat & XD1_OWN) == 0) 273 goto gotone; 274 DELAY(1000); /* 1 milli second */ 275 } while (--bound > 0); 276 errno = 0; 277 return -1; 278 gotone: 279 if ((rxstat & XD1_OK) == 0) { 280 rxd->xd1 = htole32(XD1_OWN | FRAMESIZE); 281 wbinv(rxd, sizeof(struct desc)); 282 l->rx ^= 1; 283 goto again; 284 } 285 /* good frame */ 286 len = (rxstat & 0xfff) - 4 /* HASFCS */; 287 if (len > maxlen) 288 len = maxlen; 289 ptr = l->store[l->rx]; 290 inv(ptr, len); 291 memcpy(buf, ptr, len); 292 rxd->xd1 = htole32(XD1_OWN | FRAMESIZE); 293 wbinv(rxd, sizeof(struct desc)); 294 l->rx ^= 1; 295 CSR_WRITE(l, SIP_CR, l->cr); 296 return len; 297 } 298 299 static int 300 read_eeprom(struct local *l, int loc) 301 { 302 #define R110 06 /* SEEPROM READ op. */ 303 unsigned data, v, i; 304 305 /* hold chip select */ 306 v = MEAR_EESEL; 307 CSR_WRITE(l, SIP_MEAR, v); 308 309 data = (R110 << 6) | (loc & 0x3f); /* 6 bit addressing */ 310 /* instruct R110 op. at loc in MSB first order */ 311 for (i = (1 << 8); i != 0; i >>= 1) { 312 if (data & i) 313 v |= MEAR_EEDI; 314 else 315 v &= ~MEAR_EEDI; 316 CSR_WRITE(l, SIP_MEAR, v); 317 CSR_WRITE(l, SIP_MEAR, v | MEAR_EECLK); 318 DELAY(4); 319 CSR_WRITE(l, SIP_MEAR, v); 320 DELAY(4); 321 } 322 v = MEAR_EESEL; 323 /* read 16bit quantity in MSB first order */ 324 data = 0; 325 for (i = 0; i < 16; i++) { 326 CSR_WRITE(l, SIP_MEAR, v | MEAR_EECLK); 327 DELAY(4); 328 data = (data << 1) | !!(CSR_READ(l, SIP_MEAR) & MEAR_EEDO); 329 CSR_WRITE(l, SIP_MEAR, v); 330 DELAY(4); 331 } 332 /* turn off chip select */ 333 CSR_WRITE(l, SIP_MEAR, 0); 334 DELAY(4); 335 return data; 336 } 337 338 #define MII_BMCR 0x00 /* Basic mode control register (rw) */ 339 #define BMCR_RESET 0x8000 /* reset */ 340 #define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ 341 #define BMCR_ISO 0x0400 /* isolate */ 342 #define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ 343 #define MII_BMSR 0x01 /* Basic mode status register (ro) */ 344 #define BMSR_ACOMP 0x0020 /* Autonegotiation complete */ 345 #define BMSR_LINK 0x0004 /* Link status */ 346 #define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */ 347 #define ANAR_FC 0x0400 /* local device supports PAUSE */ 348 #define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ 349 #define ANAR_TX 0x0080 /* local device supports 100bTx */ 350 #define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ 351 #define ANAR_10 0x0020 /* local device supports 10bT */ 352 #define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ 353 #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ 354 355 unsigned 356 mii_read(struct local *l, int phy, int reg) 357 { 358 unsigned val; 359 360 do { 361 val = CSR_READ(l, SIP_BMCR + (reg << 2)); 362 } while (reg == MII_BMSR && val == 0); 363 return val & 0xffff; 364 } 365 366 void 367 mii_write(struct local *l, int phy, int reg, int val) 368 { 369 370 CSR_WRITE(l, SIP_BMCR + (reg << 2), val); 371 } 372 373 void 374 mii_initphy(struct local *l) 375 { 376 int phy, ctl, sts, bound; 377 378 for (phy = 0; phy < 32; phy++) { 379 ctl = mii_read(l, phy, MII_BMCR); 380 sts = mii_read(l, phy, MII_BMSR); 381 if (ctl != 0xffff && sts != 0xffff) 382 goto found; 383 } 384 printf("MII: no PHY found\n"); 385 return; 386 found: 387 ctl = mii_read(l, phy, MII_BMCR); 388 mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET); 389 bound = 100; 390 do { 391 DELAY(10); 392 ctl = mii_read(l, phy, MII_BMCR); 393 if (ctl == 0xffff) { 394 printf("MII: PHY %d has died after reset\n", phy); 395 return; 396 } 397 } while (bound-- > 0 && (ctl & BMCR_RESET)); 398 if (bound == 0) { 399 printf("PHY %d reset failed\n", phy); 400 } 401 ctl &= ~BMCR_ISO; 402 mii_write(l, phy, MII_BMCR, ctl); 403 sts = mii_read(l, phy, MII_BMSR) | 404 mii_read(l, phy, MII_BMSR); /* read twice */ 405 l->phy = phy; /* should be 0 */ 406 l->bmsr = sts; 407 } 408 409 void 410 mii_dealan(struct local *l, unsigned timo) 411 { 412 unsigned anar, bound; 413 414 anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA; 415 mii_write(l, l->phy, MII_ANAR, anar); 416 mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 417 l->anlpar = 0; 418 bound = getsecs() + timo; 419 do { 420 l->bmsr = mii_read(l, l->phy, MII_BMSR) | 421 mii_read(l, l->phy, MII_BMSR); /* read twice */ 422 if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) { 423 l->anlpar = mii_read(l, l->phy, MII_ANLPAR); 424 break; 425 } 426 DELAY(10 * 1000); 427 } while (getsecs() < bound); 428 return; 429 } 430