1 /* $NetBSD: kse.c,v 1.1 2011/01/23 01:05:30 nisimura Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 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_4(l, r) in32rb((l)->csr+(r)) 48 #define CSR_WRITE_4(l, r, v) out32rb((l)->csr+(r), (v)) 49 #define CSR_READ_2(l, r) in16rb((l)->csr+(r)) 50 #define CSR_WRITE_2(l, r, v) out16rb((l)->csr+(r), (v)) 51 #define VTOPHYS(va) (uint32_t)(va) 52 #define DEVTOV(pa) (uint32_t)(pa) 53 #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz)) 54 #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz)) 55 #define DELAY(n) delay(n) 56 #define ALLOC(T,A) (T *)allocaligned(sizeof(T),(A)) 57 58 struct desc { 59 uint32_t xd0, xd1, xd2, xd3; 60 }; 61 #define T0_OWN (1U<<31) /* desc is ready to Tx */ 62 #define T1_IC (1U<<31) /* post interrupt on complete */ 63 #define T1_FS (1U<<30) /* first segment of frame */ 64 #define T1_LS (1U<<29) /* last segment of frame */ 65 #define T1_TER (1U<<25) /* end of ring */ 66 #define T1_SPN 0x00300000 /* 21:20 switch port 1/2 */ 67 #define T1_TBS_MASK 0x7ff /* segment size 10:0 */ 68 69 #define R0_OWN (1U<<31) /* desc is empty */ 70 #define R0_FS (1U<<30) /* first segment of frame */ 71 #define R0_LS (1U<<29) /* last segment of frame */ 72 #define R0_IPE (1U<<28) /* IP checksum error */ 73 #define R0_TCPE (1U<<27) /* TCP checksum error */ 74 #define R0_UDPE (1U<<26) /* UDP checksum error */ 75 #define R0_ES (1U<<25) /* error summary */ 76 #define R0_MF (1U<<24) /* multicast frame */ 77 #define R0_SPN 0x00300000 /* 21:20 switch port 1/2 */ 78 #define R0_RE (1U<<19) /* MII reported error */ 79 #define R0_TL (1U<<18) /* frame too long, beyond 1518 */ 80 #define R0_RF (1U<<17) /* damaged runt frame */ 81 #define R0_CE (1U<<16) /* CRC error */ 82 #define R0_FT (1U<<15) /* frame type */ 83 #define R0_FL_MASK 0x7ff /* frame length 10:0 */ 84 #define R1_RER (1U<<25) /* end of ring */ 85 #define R1_RBS_MASK 0x7fc /* segment size 10:0 */ 86 87 #define MDTXC 0x000 /* DMA transmit control */ 88 #define MDRXC 0x004 /* DMA receive control */ 89 #define MDTSC 0x008 /* DMA transmit start */ 90 #define MDRSC 0x00c /* DMA receive start */ 91 #define TDLB 0x010 /* transmit descriptor list base */ 92 #define RDLB 0x014 /* receive descriptor list base */ 93 #define MARL 0x200 /* MAC address low */ 94 #define MARM 0x202 /* MAC address middle */ 95 #define MARH 0x204 /* MAC address high */ 96 #define CIDR 0x400 /* chip ID and enable */ 97 #define P1CR4 0x512 /* port 1 control 4 */ 98 #define P1SR 0x514 /* port 1 status */ 99 100 #define FRAMESIZE 1536 101 102 struct local { 103 struct desc txd[2]; 104 struct desc rxd[2]; 105 uint8_t rxstore[2][FRAMESIZE]; 106 unsigned csr, tx, rx; 107 }; 108 109 static void mii_dealan(struct local *, unsigned); 110 111 int 112 kse_match(unsigned tag, void *data) 113 { 114 unsigned v; 115 116 v = pcicfgread(tag, PCI_ID_REG); 117 switch (v) { 118 case PCI_DEVICE(0x16c6, 0x8841): 119 case PCI_DEVICE(0x16c6, 0x8842): 120 return 1; 121 } 122 return 0; 123 } 124 125 void * 126 kse_init(unsigned tag, void *data) 127 { 128 struct local *l; 129 struct desc *txd, *rxd; 130 unsigned i, val, fdx; 131 uint8_t *en; 132 133 l = ALLOC(struct local, 32); /* desc alignment */ 134 memset(l, 0, sizeof(struct local)); 135 l->csr = DEVTOV(pcicfgread(tag, 0x10)); 136 137 en = data; 138 i = CSR_READ_2(l, MARL); 139 en[0] = i; 140 en[1] = i >> 8; 141 i = CSR_READ_2(l, MARM); 142 en[2] = i; 143 en[3] = i >> 8; 144 i = CSR_READ_2(l, MARH); 145 en[4] = i; 146 en[5] = i >> 8; 147 148 printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", 149 en[0], en[1], en[2], en[3], en[4], en[5]); 150 151 CSR_WRITE_2(l, CIDR, 1); 152 153 mii_dealan(l, 5); 154 155 val = pcicfgread(tag, PCI_ID_REG); 156 if (PCI_PRODUCT(val) == 0x8841) { 157 val = CSR_READ_2(l, P1SR); 158 fdx = !!(val & (1U << 9)); 159 printf("%s", (val & (1U << 8)) ? "100Mbps" : "10Mbps"); 160 if (fdx) 161 printf("-FDX"); 162 printf("\n"); 163 } 164 165 txd = &l->txd[0]; 166 rxd = &l->rxd[0]; 167 rxd[0].xd0 = htole32(R0_OWN); 168 rxd[0].xd1 = htole32(FRAMESIZE); 169 rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0])); 170 rxd[0].xd3 = htole32(VTOPHYS(&rxd[1])); 171 rxd[1].xd0 = htole32(R0_OWN); 172 rxd[1].xd1 = htole32(R1_RER | FRAMESIZE); 173 rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1])); 174 rxd[1].xd3 = htole32(VTOPHYS(&rxd[0])); 175 l->tx = l->rx = 0; 176 177 CSR_WRITE_4(l, TDLB, VTOPHYS(txd)); 178 CSR_WRITE_4(l, RDLB, VTOPHYS(rxd)); 179 CSR_WRITE_4(l, MDTXC, 07); /* stretch short, add CRC, Tx enable */ 180 CSR_WRITE_4(l, MDRXC, 01); /* Rx enable */ 181 CSR_WRITE_4(l, MDRSC, 01); /* start receiving */ 182 183 return l; 184 } 185 186 int 187 kse_send(void *dev, char *buf, unsigned len) 188 { 189 struct local *l = dev; 190 volatile struct desc *txd; 191 unsigned txstat, loop; 192 193 wbinv(buf, len); 194 txd = &l->txd[l->tx]; 195 txd->xd2 = htole32(VTOPHYS(buf)); 196 txd->xd1 = htole32(T1_FS | T1_LS | (len & T1_TBS_MASK)); 197 txd->xd0 = htole32(T0_OWN); 198 wbinv(txd, sizeof(struct desc)); 199 CSR_WRITE_4(l, MDTSC, 01); /* start transmission */ 200 loop = 100; 201 do { 202 txstat = le32toh(txd->xd0); 203 if ((txstat & T0_OWN) == 0) 204 goto done; 205 DELAY(10); 206 inv(txd, sizeof(struct desc)); 207 } while (--loop != 0); 208 printf("xmit failed\n"); 209 return -1; 210 done: 211 l->tx ^= 1; 212 return len; 213 } 214 215 int 216 kse_recv(void *dev, char *buf, unsigned maxlen, unsigned timo) 217 { 218 struct local *l = dev; 219 volatile struct desc *rxd; 220 unsigned bound, rxstat, len; 221 uint8_t *ptr; 222 223 bound = 1000 * timo; 224 printf("recving with %u sec. timeout\n", timo); 225 again: 226 rxd = &l->rxd[l->rx]; 227 do { 228 inv(rxd, sizeof(struct desc)); 229 rxstat = le32toh(rxd->xd0); 230 if ((rxstat & R0_OWN) == 0) 231 goto gotone; 232 DELAY(1000); /* 1 milli second */ 233 } while (--bound > 0); 234 errno = 0; 235 return -1; 236 gotone: 237 if (rxstat & R0_ES) { 238 rxd->xd0 = htole32(R0_OWN); 239 wbinv(rxd, sizeof(struct desc)); 240 l->rx ^= 1; 241 CSR_WRITE_4(l, MDRSC, 01); /* restart receiving */ 242 goto again; 243 } 244 /* good frame */ 245 len = (rxstat & R0_FL_MASK) - 4 /* HASFCS */; 246 if (len > maxlen) 247 len = maxlen; 248 ptr = l->rxstore[l->rx]; 249 inv(ptr, len); 250 memcpy(buf, ptr, len); 251 rxd->xd0 = htole32(R0_OWN); 252 wbinv(rxd, sizeof(struct desc)); 253 l->rx ^= 1; 254 CSR_WRITE_4(l, MDRSC, 01); /* necessary? */ 255 return len; 256 } 257 258 void 259 mii_dealan(struct local *l, unsigned timo) 260 { 261 unsigned val, bound; 262 263 val = (1U << 13) | (1U << 7) | 0x1f /* advertise all caps */; 264 CSR_WRITE_2(l, P1CR4, val); 265 bound = getsecs() + timo; 266 do { 267 val = CSR_READ_2(l, P1SR); 268 if (val & (1U << 5)) /* link is found up */ 269 break; 270 DELAY(10 * 1000); 271 } while (getsecs() < bound); 272 return; 273 } 274