]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/contrib/dev/oltr/if_oltr_pci.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / contrib / dev / oltr / if_oltr_pci.c
1 /*
2  * Copyright (c) 1998, Larry Lile
3  * All rights reserved.
4  *
5  * For latest sources and information on this driver, please
6  * go to http://anarchy.stdio.com.
7  *
8  * Questions, comments or suggestions should be directed to
9  * Larry Lile <lile@stdio.com>.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice unmodified, this list of conditions, and the following
16  *    disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD$
34  */
35
36 #include <sys/param.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/socket.h>
41
42 #include <net/if.h>
43 #include <net/if_arp.h>
44 #include <net/iso88025.h>
45 #include <net/if_media.h>
46 #include <net/bpf.h>
47
48 #include <vm/vm.h>              /* for vtophys */
49 #include <vm/pmap.h>            /* for vtophys */
50
51 #include <machine/bus.h>
52 #include <machine/resource.h>
53
54 #include <sys/bus.h>
55 #include <sys/rman.h>
56
57 #if (__FreeBSD_version < 500000)
58 #include <pci/pcireg.h>
59 #include <pci/pcivar.h>
60 #else
61 #include <dev/pci/pcireg.h>
62 #include <dev/pci/pcivar.h>
63 #endif
64
65 #include "contrib/dev/oltr/trlld.h"
66 #include "contrib/dev/oltr/if_oltrvar.h"
67
68 static int oltr_pci_probe       __P((device_t));
69 static int oltr_pci_attach      __P((device_t));
70 static int oltr_pci_detach      __P((device_t));
71 static void oltr_pci_shutdown   __P((device_t));
72
73 extern TRlldDriver_t LldDriver;
74
75 struct AdapterNameEntry {
76         int type;
77         char *name; } ;
78
79 static struct AdapterNameEntry AdapterNameList[] = {
80         { 10, "Olicom PCI 16/4 Adapter (OC-3136)" },
81         { 11, "Olicom PCI 16/4 Adapter (OC-3136)" },
82         { 12, "Olicom PCI/II 16/4 Adapter (OC-3137)" },
83         { 13, "Olicom PCI 16/4 Adapter (OC-3139)" },
84         { 14, "Olicom RapidFire 3140 16/4 PCI Adapter (OC-3140)" },
85         { 15, "Olicom RapidFire 3141 Fiber Adapter (OC-3141)" },
86         { 19, "Olicom RapidFire 3540 100/16/4 Adapter (OC-3540)" },
87         {  0, "Olicom Unsupported Adapter" }
88 };
89
90 static device_method_t oltr_methods[] = {
91         DEVMETHOD(device_probe,         oltr_pci_probe),
92         DEVMETHOD(device_attach,        oltr_pci_attach),
93         DEVMETHOD(device_detach,        oltr_pci_detach),
94         DEVMETHOD(device_shutdown,      oltr_pci_shutdown),
95         { 0, 0 }
96 };
97
98 static driver_t oltr_driver = {
99         "oltr",
100         oltr_methods,
101         sizeof(struct oltr_softc)
102 };
103
104 static devclass_t oltr_devclass;
105
106 DRIVER_MODULE(oltr, pci, oltr_driver, oltr_devclass, 0, 0);
107 MODULE_DEPEND(oltr, pci, 1, 1, 1);
108 MODULE_DEPEND(oltr, iso88025, 1, 1, 1);
109
110 static int
111 oltr_pci_probe(device_t dev)
112 {
113         int                     i, rc;
114         char                    PCIConfigHeader[64];
115         TRlldAdapterConfig_t    config;
116         struct AdapterNameEntry *list = AdapterNameList;
117
118         if ((pci_get_vendor(dev) == PCI_VENDOR_OLICOM) &&
119            ((pci_get_device(dev) == 0x0001) ||
120             (pci_get_device(dev) == 0x0004) ||
121             (pci_get_device(dev) == 0x0005) ||
122             (pci_get_device(dev) == 0x0007) ||
123             (pci_get_device(dev) == 0x0008))) {
124
125                 for (i = 0; i < sizeof(PCIConfigHeader); i++)
126                         PCIConfigHeader[i] = pci_read_config(dev, i, 1);
127
128                 rc = TRlldPCIConfig(&LldDriver, &config, PCIConfigHeader);
129                 if (rc == TRLLD_PCICONFIG_FAIL) {
130                         device_printf(dev, "TRlldPciConfig failed!\n");
131                         return(ENXIO);
132                 }
133                 if (rc == TRLLD_PCICONFIG_VERSION) {
134                         device_printf(dev, "wrong LLD version\n");
135                         return(ENXIO);
136                 }
137                 while (list->type != 0 && list->type != config.type)
138                         list++;
139                 device_set_desc(dev, list->name);
140                 return(0);
141         }
142         return(ENXIO);
143 }
144
145 static int
146 oltr_pci_attach(device_t dev)
147 {
148         int                     i, s, scratch_size;
149         u_long                  command;
150         char                    PCIConfigHeader[64];
151         struct oltr_softc               *sc = device_get_softc(dev);
152
153         s = splimp();
154
155         bzero(sc, sizeof(struct oltr_softc));
156         sc->unit = device_get_unit(dev);
157         sc->state = OL_UNKNOWN;
158
159         for (i = 0; i < sizeof(PCIConfigHeader); i++)
160                 PCIConfigHeader[i] = pci_read_config(dev, i, 1);
161
162         switch(TRlldPCIConfig(&LldDriver, &sc->config, PCIConfigHeader)) {
163         case TRLLD_PCICONFIG_OK:
164                 break;
165         case TRLLD_PCICONFIG_SET_COMMAND:
166                 device_printf(dev, "enabling bus master mode\n");
167                 command = pci_read_config(dev, PCIR_COMMAND, 4);
168                 pci_write_config(dev, PCIR_COMMAND,
169                         (command | PCIM_CMD_BUSMASTEREN), 4);
170                 command = pci_read_config(dev, PCIR_COMMAND, 4);
171                 if (!(command & PCIM_CMD_BUSMASTEREN)) {
172                         device_printf(dev, "failed to enable bus master mode\n");
173                         goto config_failed;
174                 }
175                 break;
176         case TRLLD_PCICONFIG_FAIL:
177                 device_printf(dev, "TRlldPciConfig failed!\n");
178                 goto config_failed;
179                 break;
180         case TRLLD_PCICONFIG_VERSION:
181                 device_printf(dev, "wrong LLD version\n");
182                 goto config_failed;
183                 break;
184         }
185         device_printf(dev, "MAC address %6D\n", sc->config.macaddress, ":");
186
187         scratch_size = TRlldAdapterSize();
188         if (bootverbose)
189                 device_printf(dev, "adapter memory block size %d bytes\n", scratch_size);
190         sc->TRlldAdapter = (TRlldAdapter_t)malloc(scratch_size, M_DEVBUF, M_NOWAIT);
191         if (sc->TRlldAdapter == NULL) {
192                 device_printf(dev, "couldn't allocate scratch buffer (%d bytes)\n", scratch_size);
193                 goto config_failed;
194         }
195         sc->TRlldAdapter_phys = vtophys(sc->TRlldAdapter);
196
197         /*
198          * Allocate RX/TX Pools
199          */
200         for (i = 0; i < RING_BUFFER_LEN; i++) {
201                 sc->rx_ring[i].index = i;
202                 sc->rx_ring[i].data = (char *)malloc(RX_BUFFER_LEN, M_DEVBUF, M_NOWAIT);
203                 sc->rx_ring[i].address = vtophys(sc->rx_ring[i].data);
204                 sc->tx_ring[i].index = i;
205                 sc->tx_ring[i].data = (char *)malloc(TX_BUFFER_LEN, M_DEVBUF, M_NOWAIT);
206                 sc->tx_ring[i].address = vtophys(sc->tx_ring[i].data);
207                 if ((!sc->rx_ring[i].data) || (!sc->tx_ring[i].data)) {
208                         device_printf(dev, "unable to allocate ring buffers\n");
209                         while (i > 0) {
210                                 if (sc->rx_ring[i].data)
211                                         free(sc->rx_ring[i].data, M_DEVBUF);
212                                 if (sc->tx_ring[i].data)
213                                         free(sc->tx_ring[i].data, M_DEVBUF);
214                                 i--;
215                         }
216                         goto config_failed;
217                 }
218         }
219         
220         if (oltr_attach(dev) == -1)
221                 goto config_failed;
222
223         splx(s);
224         return(0);
225
226 config_failed:
227
228         splx(s);
229         return(ENXIO);
230 }
231
232 static int
233 oltr_pci_detach(device_t dev)
234 {
235         struct oltr_softc       *sc = device_get_softc(dev);
236         struct ifnet            *ifp = sc->ifp;
237         int s, i;
238
239         device_printf(dev, "driver unloading\n");
240
241         s = splimp();
242
243         iso88025_ifdetach(ifp, ISO88025_BPF_SUPPORTED);
244         if (sc->state > OL_CLOSED)
245                 oltr_stop(sc);
246
247         untimeout(oltr_poll, (void *)sc, sc->oltr_poll_ch);
248         /*untimeout(oltr_stat, (void *)sc, sc->oltr_stat_ch);*/
249
250         bus_teardown_intr(dev, sc->irq_res, sc->oltr_intrhand);
251         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
252
253         if_free(ifp);
254
255         /* Deallocate all dynamic memory regions */
256         for (i = 0; i < RING_BUFFER_LEN; i++) {
257                 free(sc->rx_ring[i].data, M_DEVBUF);
258                 free(sc->tx_ring[i].data, M_DEVBUF);
259         }
260         if (sc->work_memory)
261                 free(sc->work_memory, M_DEVBUF);
262         free(sc->TRlldAdapter, M_DEVBUF);
263
264         (void)splx(s);
265
266         return(0);
267 }
268
269 static void
270 oltr_pci_shutdown(device_t dev)
271 {
272         struct oltr_softc               *sc = device_get_softc(dev);
273
274         device_printf(dev, "oltr_pci_shutdown called\n");
275
276         if (sc->state > OL_CLOSED)
277                 oltr_stop(sc);
278
279         return;
280 }