1 /* $NetBSD: nvt.c,v 1.3 2011/10/30 21:08:33 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_WRITE_1(l, r, v)  out8((l)->csr+(r), (v))
48 #define CSR_READ_1(l, r)      in8((l)->csr+(r))
49 #define CSR_WRITE_2(l, r, v)  out16rb((l)->csr+(r), (v))
50 #define CSR_READ_2(l, r)      in16rb((l)->csr+(r))
51 #define CSR_WRITE_4(l, r, v)  out32rb((l)->csr+(r), (v))
52 #define CSR_READ_4(l, r)      in32rb((l)->csr+(r))
53 #define VTOPHYS(va)           (uint32_t)(va)
54 #define DEVTOV(pa)            (uint32_t)(pa)
55 #define wbinv(adr, siz)                 _wbinv(VTOPHYS(adr), (uint32_t)(siz))
56 #define inv(adr, siz)                   _inv(VTOPHYS(adr), (uint32_t)(siz))
57 #define DELAY(n)              delay(n)
58 #define ALLOC(T,A)            (T *)allocaligned(sizeof(T),(A))
59 
60 struct desc {
61           uint32_t xd0, xd1, xd2, xd3;
62 };
63 #define T0_OWN                (1U << 31)          /* 1: loaded for HW to send */
64 #define T0_TERR               (1U << 15)          /* Tx error; ABT|CBH */
65 #define T0_UDF                (1U << 11)          /* FIFO underflow */
66 #define T0_CRS                (1U << 10)          /* found carrier sense lost */
67 #define T0_OWC                (1U << 9) /* found out of window collision */
68 #define T0_ABT                (1U << 8) /* excess collision Tx abort */
69 #define T0_CBH                (1U << 7) /* heartbeat check failure */
70 #define T0_COLS               (1U << 4) /* collision detected */
71 #define T0_NCRMASK  0x3                 /* number of collision retries */
72 #define T1_IC                 (1U << 23)          /* post Tx done interrupt */
73 #define T1_STP                (1U << 22)          /* first frame segment */
74 #define T1_EDP                (1U << 21)          /* last frame segment */
75 #define T1_CRC                (1U << 16)          /* _disable_ CRC generation */
76 #define T1_CHN                (1U << 15)          /* "more bit," not the last seg. */
77 #define T_FLMASK    0x00007fff          /* Tx frame/segment length */
78 
79 #define R0_OWN                (1U << 31)          /* 1: empty for HW to load anew */
80 #define R0_FLMASK   0x7fff0000          /* frame length */
81 #define R0_RXOK               (1U << 15)
82 #define R0_MAR                (1U << 13)          /* multicast frame */
83 #define R0_BAR                (1U << 12)          /* broadcast frame */
84 #define R0_PHY                (1U << 11)          /* unicast frame */
85 #define R0_CHN                (1U << 10)          /* "more bit," not the last seg. */
86 #define R0_STP                (1U << 9) /* first frame segment */
87 #define R0_EDP                (1U << 8) /* last frame segment */
88 #define R0_BUFF               (1U << 7) /* segment chain was broken */
89 #define R0_RUNT               (1U << 5) /* runt frame received */
90 #define R0_LONG               (1U << 4) /* frame too long */
91 #define R0_FOV                (1U << 3) /* Rx FIFO overflow */
92 #define R0_FAE                (1U << 2) /* frame alignment error */
93 #define R0_CRCE               (1U << 1) /* CRC error */
94 #define R0_RERR               (1U << 0) /* Rx error summary */
95 #define R1_FLMASK   0x00007ffc          /* Rx segment buffer length */
96 
97 #define VR_PAR0               0x00                /* SA [0] */
98 #define VR_PAR1               0x01                /* SA [1] */
99 #define VR_PAR2               0x02                /* SA [2] */
100 #define VR_PAR3               0x03                /* SA [3] */
101 #define VR_PAR4               0x04                /* SA [4] */
102 #define VR_PAR5               0x05                /* SA [5] */
103 #define VR_RCR                0x06                /* Rx control */
104 #define  RCR_PROM   (1U << 4) /* accept any frame */
105 #define  RCR_AB               (1U << 3) /* accept broadcast frame */
106 #define  RCR_AM               (1U << 2) /* use multicast filter */
107 #define VR_TCR                0x07                /* Tx control */
108 #define VR_CTL0               0x08                /* control #0 */
109 #define  CTL0_RDMD  (1U << 6) /* instruct Rx descriptor poll */
110 #define  CTL0_TDMD  (1U << 5) /* instruct Tx descriptor poll */
111 #define  CTL0_TXON  (1U << 4) /* enable Tx DMA */
112 #define  CTL0_RXON  (1U << 3) /* enable Rx DMA */
113 #define  CTL0_STOP  (1U << 2) /* activate stop processing */
114 #define  CTL0_START (1U << 1) /* start and activate */
115 #define VR_CTL1               0x09                /* control #1 */
116 #define  CTL1_RESET (1U << 7) /* SW reset, self-clearing */
117 #define  CTL1_DPOLL (1U << 3) /* _disable_ Tx auto polling */
118 #define  CTL1_FDX   (1U << 2) /* set full duplex */
119 #define VR_ISR                0x0c                /* interrupt status */
120 #define VR_IEN                0x0e                /* interrupt enable */
121 #define VR_RDBA               0x18                /* Rx descriptor list base */
122 #define VR_TDBA               0x1c                /* Tx descriptor list base */
123 #define VR_MIICFG   0x6c                /* 4:0 PHY number */
124 #define VR_MIISR    0x6d                /* MII status */
125 #define VR_MIICR    0x70                /* MII control */
126 #define  MIICR_MAUTO          (1U << 7) /* activate autopoll mode */
127 #define  MIICR_RCMD (1U << 6) /* MII read operation */
128 #define  MIICR_WCMD (1U << 5) /* MII write operation */
129 #define VR_MIIADR   0x71                /* MII indirect */
130 #define  MIIADR_MIDLE         (1U << 7) /* not in auto polling */
131 #define VR_MIIDATA  0x72                /* MII read/write */
132 #define VR_RXC                0x7e                /* Rx feature control */
133 #define VR_TXC                0x7f                /* Tx feature control */
134 #define VR_MCR0               0x80                /* misc control #0 */
135 #define  MCR0_RFDXFLC         (1U << 3) /* FCR1? */
136 #define  MCR0_HDXFLC          (1U << 2) /* FCR2? */
137 #define VR_MCR1               0x81                /* misc control #1 */
138 
139 #define FRAMESIZE   1536
140 
141 struct local {
142           struct desc txd[2];
143           struct desc rxd[2];
144           uint8_t rxstore[2][FRAMESIZE];
145           unsigned csr, tx, rx;
146           unsigned phy, bmsr, anlpar;
147           unsigned ctl0;
148 };
149 
150 static void mii_autopoll(struct local *);
151 static void mii_stoppoll(struct local *);
152 static int mii_read(struct local *, int, int);
153 static void mii_write(struct local *, int, int, int);
154 static void mii_dealan(struct local *, unsigned);
155 
156 int
nvt_match(unsigned tag,void * data)157 nvt_match(unsigned tag, void *data)
158 {
159           unsigned v;
160 
161           v = pcicfgread(tag, PCI_ID_REG);
162           switch (v) {
163           case PCI_DEVICE(0x1106, 0x3053):
164           case PCI_DEVICE(0x1106, 0x3065):
165                     return 1;
166           }
167           return 0;
168 }
169 
170 void *
nvt_init(unsigned tag,void * data)171 nvt_init(unsigned tag, void *data)
172 {
173           unsigned val, fdx;
174           struct local *l;
175           struct desc *txd, *rxd;
176           uint8_t *en;
177 
178           l = ALLOC(struct local, 32); /* desc alignment */
179           memset(l, 0, sizeof(struct local));
180           l->csr = ~01 & DEVTOV(pcicfgread(tag, 0x10)); /* use IO space */
181 
182           val = CTL1_RESET;
183           CSR_WRITE_1(l, VR_CTL1, val);
184           do {
185                     val = CSR_READ_1(l, VR_CTL1);
186           } while (val & CTL1_RESET);
187           /* PHY number is loaded from EEPROM */
188           l->phy = CSR_READ_1(l, VR_MIICFG) & 0x1f;
189 
190           en = data;
191           en[0] = CSR_READ_1(l, VR_PAR0);
192           en[1] = CSR_READ_1(l, VR_PAR1);
193           en[2] = CSR_READ_1(l, VR_PAR2);
194           en[3] = CSR_READ_1(l, VR_PAR3);
195           en[4] = CSR_READ_1(l, VR_PAR4);
196           en[5] = CSR_READ_1(l, VR_PAR5);
197 
198           printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
199               en[0], en[1], en[2], en[3], en[4], en[5]);
200           DPRINTF(("PHY %d (%04x.%04x)\n", l->phy,
201               mii_read(l, l->phy, 2), mii_read(l, l->phy, 3)));
202 
203           mii_dealan(l, 5);
204 
205           /* speed and duplexity can be seen in MII 20 */
206           val = mii_read(l, l->phy, 20);
207           fdx = !!(val & (1U << 0));
208           printf("%s", (val & (1U << 1)) ? "100Mbps" : "10Mbps");
209           if (fdx)
210                     printf("-FDX");
211           printf("\n");
212 
213           txd = &l->txd[0];
214           rxd = &l->rxd[0];
215           rxd[0].xd0 = htole32(R0_OWN);
216           rxd[0].xd1 = htole32(FRAMESIZE << 16);
217           rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
218           rxd[0].xd3 = htole32(VTOPHYS(&rxd[1]));
219           rxd[1].xd0 = htole32(R0_OWN);
220           rxd[1].xd1 = htole32(VTOPHYS(l->rxstore[1]));
221           rxd[1].xd2 = htole32(FRAMESIZE << 16);
222           rxd[1].xd3 = htole32(VTOPHYS(&rxd[0]));
223           wbinv(l, sizeof(struct local));
224           l->tx = l->rx = 0;
225 
226           /* enable transmitter and receiver */
227           l->ctl0 = CTL0_TXON | CTL0_RXON | CTL0_START;
228           CSR_WRITE_4(l, VR_RDBA, VTOPHYS(rxd));
229           CSR_WRITE_4(l, VR_TDBA, VTOPHYS(txd));
230           CSR_WRITE_1(l, VR_RCR, 0);
231           CSR_WRITE_1(l, VR_TCR, 0);
232           CSR_WRITE_2(l, VR_ISR, ~0);
233           CSR_WRITE_2(l, VR_IEN, 0);
234           if (fdx)
235                     CSR_WRITE_1(l, VR_CTL1, CTL1_FDX);
236           CSR_WRITE_1(l, VR_CTL0, CTL0_START);
237           CSR_WRITE_1(l, VR_CTL0, l->ctl0);
238 
239           return l;
240 }
241 
242 int
nvt_send(void * dev,char * buf,unsigned len)243 nvt_send(void *dev, char *buf, unsigned len)
244 {
245           struct local *l = dev;
246           volatile struct desc *txd;
247           unsigned loop;
248 
249           len = (len & T_FLMASK);
250           if (len < 60)
251                     len = 60; /* needs to stretch to ETHER_MIN_LEN - 4 */
252           wbinv(buf, len);
253           txd = &l->txd[l->tx];
254           txd->xd3 = htole32(txd);
255           txd->xd2 = htole32(VTOPHYS(buf));
256           txd->xd1 = htole32(T1_STP | T1_EDP | len);
257           txd->xd0 = htole32(T0_OWN);
258           wbinv(txd, sizeof(struct desc));
259           CSR_WRITE_1(l, VR_CTL0, l->ctl0 | CTL0_TDMD);
260           loop = 100;
261           do {
262                     if ((le32toh(txd->xd0) & T0_OWN) == 0)
263                               goto done;
264                     DELAY(10);
265                     inv(txd, sizeof(struct desc));
266           } while (--loop > 0);
267           printf("xmit failed\n");
268           return -1;
269   done:
270           l->tx ^= 1;
271           return len;
272 }
273 
274 int
nvt_recv(void * dev,char * buf,unsigned maxlen,unsigned timo)275 nvt_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
276 {
277           struct local *l = dev;
278           volatile struct desc *rxd;
279           unsigned bound, rxstat, len;
280           uint8_t *ptr;
281 
282           bound = 1000 * timo;
283 printf("recving with %u sec. timeout\n", timo);
284   again:
285           rxd = &l->rxd[l->rx];
286           do {
287                     inv(rxd, sizeof(struct desc));
288                     rxstat = le32toh(rxd->xd0);
289                     if ((rxstat & R0_OWN) == 0)
290                               goto gotone;
291                     DELAY(1000);        /* 1 milli second */
292           } while (--bound > 0);
293           errno = 0;
294           return -1;
295   gotone:
296           if ((rxstat & R0_RXOK) == 0) {
297                     rxd->xd0 = htole32(R0_OWN);
298                     wbinv(rxd, sizeof(struct desc));
299                     l->rx ^= 1;
300                     goto again;
301           }
302           len = ((rxstat & R0_FLMASK) >> 16) - 4 /* HASFCS */;
303           if (len > maxlen)
304                     len = maxlen;
305           ptr = l->rxstore[l->rx];
306           inv(ptr, len);
307           memcpy(buf, ptr, len);
308           rxd->xd0 = htole32(R0_OWN);
309           wbinv(rxd, sizeof(struct desc));
310           l->rx ^= 1;
311           return len;
312 }
313 
314 static void
mii_autopoll(struct local * l)315 mii_autopoll(struct local *l)
316 {
317           int v;
318 
319           CSR_WRITE_1(l, VR_MIICR, 0);
320           do {
321                     DELAY(1);
322                     v = CSR_READ_1(l, VR_MIISR);
323           } while ((v & MIIADR_MIDLE) == 0);
324           CSR_WRITE_1(l, VR_MIICR, MIICR_MAUTO);
325           do {
326                     DELAY(1);
327                     v = CSR_READ_1(l, VR_MIISR);
328           } while ((v & MIIADR_MIDLE) != 0);
329 }
330 
331 static void
mii_stoppoll(struct local * l)332 mii_stoppoll(struct local *l)
333 {
334           int v;
335 
336           CSR_WRITE_1(l, VR_MIICR, 0);
337           do {
338                     DELAY(1);
339                     v = CSR_READ_1(l, VR_MIISR);
340           } while ((v & MIIADR_MIDLE) == 0);
341 }
342 
343 static int
mii_read(struct local * l,int phy,int reg)344 mii_read(struct local *l, int phy, int reg)
345 {
346           int v;
347 
348           mii_stoppoll(l);
349           CSR_WRITE_1(l, VR_MIICFG, phy);
350           CSR_WRITE_1(l, VR_MIIADR, reg);
351           CSR_WRITE_1(l, VR_MIICR, MIICR_RCMD);
352           do {
353                     v = CSR_READ_1(l, VR_MIICR);
354           } while (v & MIICR_RCMD);
355           v = CSR_READ_2(l, VR_MIIDATA);
356           mii_autopoll(l);
357           return v;
358 }
359 
360 static void
mii_write(struct local * l,int phy,int reg,int data)361 mii_write(struct local *l, int phy, int reg, int data)
362 {
363           int v;
364 
365           mii_stoppoll(l);
366           CSR_WRITE_2(l, VR_MIIDATA, data);
367           CSR_WRITE_1(l, VR_MIICFG, phy);
368           CSR_WRITE_1(l, VR_MIIADR, reg);
369           CSR_WRITE_1(l, VR_MIICR, MIICR_WCMD);
370           do {
371                     v = CSR_READ_1(l, VR_MIICR);
372           } while (v & MIICR_WCMD);
373           mii_autopoll(l);
374 }
375 
376 #define MII_BMCR    0x00      /* Basic mode control register (rw) */
377 #define  BMCR_RESET 0x8000    /* reset */
378 #define  BMCR_AUTOEN          0x1000    /* autonegotiation enable */
379 #define  BMCR_ISO   0x0400    /* isolate */
380 #define  BMCR_STARTNEG        0x0200    /* restart autonegotiation */
381 #define MII_BMSR    0x01      /* Basic mode status register (ro) */
382 #define  BMSR_ACOMP 0x0020    /* Autonegotiation complete */
383 #define  BMSR_LINK  0x0004    /* Link status */
384 #define MII_ANAR    0x04      /* Autonegotiation advertisement (rw) */
385 #define  ANAR_FC    0x0400    /* local device supports PAUSE */
386 #define  ANAR_TX_FD 0x0100    /* local device supports 100bTx FD */
387 #define  ANAR_TX    0x0080    /* local device supports 100bTx */
388 #define  ANAR_10_FD 0x0040    /* local device supports 10bT FD */
389 #define  ANAR_10    0x0020    /* local device supports 10bT */
390 #define  ANAR_CSMA  0x0001    /* protocol selector CSMA/CD */
391 #define MII_ANLPAR  0x05      /* Autonegotiation lnk partner abilities (rw) */
392 
393 void
mii_dealan(struct local * l,unsigned timo)394 mii_dealan(struct local *l, unsigned timo)
395 {
396           unsigned anar, bound;
397 
398           anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
399           mii_write(l, l->phy, MII_ANAR, anar);
400           mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
401           l->anlpar = 0;
402           bound = getsecs() + timo;
403           do {
404                     l->bmsr = mii_read(l, l->phy, MII_BMSR) |
405                        mii_read(l, l->phy, MII_BMSR); /* read twice */
406                     if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
407                               l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
408                               break;
409                     }
410                     DELAY(10 * 1000);
411           } while (getsecs() < bound);
412           return;
413 }
414