if_an_pci.c revision 92739
151829Smdodd/*
251829Smdodd * Copyright (c) 1997, 1998, 1999
351829Smdodd *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
451829Smdodd *
551829Smdodd * Redistribution and use in source and binary forms, with or without
651829Smdodd * modification, are permitted provided that the following conditions
751829Smdodd * are met:
851829Smdodd * 1. Redistributions of source code must retain the above copyright
951829Smdodd *    notice, this list of conditions and the following disclaimer.
1051829Smdodd * 2. Redistributions in binary form must reproduce the above copyright
1151829Smdodd *    notice, this list of conditions and the following disclaimer in the
1251829Smdodd *    documentation and/or other materials provided with the distribution.
1351829Smdodd * 3. All advertising materials mentioning features or use of this software
1451829Smdodd *    must display the following acknowledgement:
1551829Smdodd *	This product includes software developed by Bill Paul.
1651829Smdodd * 4. Neither the name of the author nor the names of any co-contributors
1751829Smdodd *    may be used to endorse or promote products derived from this software
1851829Smdodd *    without specific prior written permission.
1951829Smdodd *
2051829Smdodd * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2151829Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2251829Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2351829Smdodd * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2451829Smdodd * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2551829Smdodd * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2651829Smdodd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2751829Smdodd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2851829Smdodd * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29119418Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30119418Sobrien * THE POSSIBILITY OF SUCH DAMAGE.
31119418Sobrien *
3251829Smdodd * $FreeBSD: head/sys/dev/an/if_an_pci.c 92739 2002-03-20 02:08:01Z alfred $
3351829Smdodd */
3451829Smdodd
35117126Sscottl/*
36117126Sscottl * This is a PCI shim for the Aironet PC4500/4800 wireless network
3751829Smdodd * driver. Aironet makes PCMCIA, ISA and PCI versions of these devices,
3851829Smdodd * which all have basically the same interface. The ISA and PCI cards
3951829Smdodd * are actually bridge adapters with PCMCIA cards inserted into them,
4051829Smdodd * however they appear as normal PCI or ISA devices to the host.
4151829Smdodd *
4251829Smdodd * All we do here is handle the PCI probe and attach and set up an
4351829Smdodd * interrupt handler entry point. The PCI version of the card uses
44135260Sphk * a PLX 9050 PCI to "dumb bus" bridge chip, which provides us with
4551829Smdodd * multiple PCI address space mappings. The primary mapping at PCI
4651829Smdodd * register 0x14 is for the PLX chip itself, *NOT* the Aironet card.
4751829Smdodd * The I/O address of the Aironet is actually at register 0x18, which
4851829Smdodd * is the local bus mapping register for bus space 0. There are also
4951829Smdodd * registers for additional register spaces at registers 0x1C and
5051829Smdodd * 0x20, but these are unused in the Aironet devices. To find out
5151829Smdodd * more, you need a datasheet for the 9050 from PLX, but you have
5251829Smdodd * to go through their sales office to get it. Bleh.
5351829Smdodd */
5451829Smdodd
5551829Smdodd#include "opt_inet.h"
5651829Smdodd
5751829Smdodd#ifdef INET
5851829Smdodd#define ANCACHE
5951829Smdodd#endif
6051829Smdodd
61122340Simp#include <sys/param.h>
6251829Smdodd#include <sys/systm.h>
63122340Simp#include <sys/sockio.h>
6451829Smdodd#include <sys/mbuf.h>
6551829Smdodd#include <sys/kernel.h>
6651829Smdodd#include <sys/socket.h>
6751829Smdodd
6851829Smdodd#include <sys/module.h>
6951829Smdodd#include <sys/bus.h>
7051829Smdodd#include <machine/bus.h>
7151829Smdodd#include <sys/rman.h>
7251829Smdodd#include <sys/lock.h>
7351829Smdodd#include <sys/mutex.h>
7451829Smdodd#include <machine/resource.h>
7551829Smdodd
7651829Smdodd#include <net/if.h>
7751829Smdodd#include <net/if_arp.h>
7851829Smdodd#include <net/ethernet.h>
7951829Smdodd#include <net/if_dl.h>
8051829Smdodd#include <net/if_media.h>
8151829Smdodd
8251829Smdodd#include <pci/pcireg.h>
8351829Smdodd#include <pci/pcivar.h>
8451829Smdodd
8551829Smdodd#ifndef lint
8651829Smdoddstatic const char rcsid[] =
8751829Smdodd "$FreeBSD: head/sys/dev/an/if_an_pci.c 92739 2002-03-20 02:08:01Z alfred $";
88122340Simp#endif
89122340Simp
90140467Simp#include <dev/an/if_aironet_ieee.h>
91140467Simp#include <dev/an/if_anreg.h>
92140467Simp
9351829Smdoddstruct an_type {
9451829Smdodd	u_int16_t		an_vid;
9551829Smdodd	u_int16_t		an_did;
9651829Smdodd	char			*an_name;
9751829Smdodd};
9851829Smdodd
9951829Smdodd#define AIRONET_VENDORID	0x14B9
10051829Smdodd#define AIRONET_DEVICEID_35x	0x0350
10151829Smdodd#define AIRONET_DEVICEID_4500	0x4500
10251829Smdodd#define AIRONET_DEVICEID_4800	0x4800
10351829Smdodd#define AIRONET_DEVICEID_4xxx	0x0001
10451829Smdodd#define AN_PCI_PLX_LOIO		0x14	/* PLX chip iobase */
10551829Smdodd#define AN_PCI_LOIO		0x18	/* Aironet iobase */
10651829Smdodd
10751829Smdoddstatic struct an_type an_devs[] = {
10851829Smdodd	{ AIRONET_VENDORID, AIRONET_DEVICEID_35x, "Cisco Aironet 350 Series" },
10951829Smdodd	{ AIRONET_VENDORID, AIRONET_DEVICEID_4500, "Aironet PCI4500" },
11051829Smdodd	{ AIRONET_VENDORID, AIRONET_DEVICEID_4800, "Aironet PCI4800" },
11151829Smdodd	{ AIRONET_VENDORID, AIRONET_DEVICEID_4xxx, "Aironet PCI4500/PCI4800" },
11251829Smdodd	{ 0, 0, NULL }
11351829Smdodd};
11451829Smdodd
11551829Smdoddstatic int an_probe_pci		(device_t);
11651829Smdoddstatic int an_attach_pci	(device_t);
11751829Smdoddstatic int an_detach_pci	(device_t);
11851829Smdodd
119122361Simpstatic int
120140467Simpan_probe_pci(device_t dev)
12151829Smdodd{
12251829Smdodd	struct an_type		*t;
12351829Smdodd
124140467Simp	t = an_devs;
125140467Simp
126140467Simp	while (t->an_name != NULL) {
127140467Simp		if (pci_get_vendor(dev) == t->an_vid &&
12851829Smdodd		    pci_get_device(dev) == t->an_did) {
12951829Smdodd			device_set_desc(dev, t->an_name);
13051829Smdodd			return(0);
13151829Smdodd		}
132140467Simp		t++;
133140467Simp	}
134140467Simp
135140467Simp	return(ENXIO);
13651829Smdodd}
13751829Smdodd
13851829Smdoddstatic int
13951829Smdoddan_attach_pci(dev)
140140467Simp	device_t		dev;
141140467Simp{
142140467Simp	u_int32_t		command;
143140467Simp	struct an_softc		*sc;
14451829Smdodd	int 			unit, flags, error = 0;
14551829Smdodd
14651829Smdodd	sc = device_get_softc(dev);
14751829Smdodd	unit = device_get_unit(dev);
148140467Simp	flags = device_get_flags(dev);
149140467Simp	bzero(sc, sizeof(struct an_softc));
15051829Smdodd
15151829Smdodd	/*
15251829Smdodd	 * Map control/status registers.
15351829Smdodd 	 */
15451829Smdodd	command = pci_read_config(dev, PCIR_COMMAND, 4);
15551829Smdodd	command |= PCIM_CMD_PORTEN;
15651829Smdodd	pci_write_config(dev, PCIR_COMMAND, command, 4);
15751829Smdodd	command = pci_read_config(dev, PCIR_COMMAND, 4);
15851829Smdodd
15951829Smdodd	if (!(command & PCIM_CMD_PORTEN)) {
16051829Smdodd		printf("an%d: failed to enable I/O ports!\n", unit);
16151829Smdodd		error = ENXIO;
162140467Simp		goto fail;
16351829Smdodd	}
164112782Smdodd
165112782Smdodd	sc->port_rid = AN_PCI_LOIO;
166112782Smdodd	error = an_alloc_port(dev, sc->port_rid, 1);
167112782Smdodd
168112782Smdodd	if (error) {
169112782Smdodd		printf("an%d: couldn't map ports\n", unit);
170112782Smdodd		goto fail;
171112782Smdodd	}
172112782Smdodd
173112782Smdodd	sc->an_btag = rman_get_bustag(sc->port_res);
174112782Smdodd	sc->an_bhandle = rman_get_bushandle(sc->port_res);
175112782Smdodd
176117126Sscottl	/* Allocate interrupt */
177117126Sscottl	error = an_alloc_irq(dev, 0, RF_SHAREABLE);
178112782Smdodd	if (error) {
17951829Smdodd		an_release_resources(dev);
18051829Smdodd		goto fail;
18151829Smdodd        }
18251829Smdodd
18351829Smdodd	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
18451829Smdodd	    an_intr, sc, &sc->irq_handle);
18551829Smdodd	if (error) {
18651829Smdodd		an_release_resources(dev);
18751829Smdodd		goto fail;
18851829Smdodd	}
18951829Smdodd
19051829Smdodd	sc->an_dev = dev;
19151829Smdodd	error = an_attach(sc, device_get_unit(dev), flags);
19251829Smdodd
19351829Smdoddfail:
19451829Smdodd	return(error);
19551829Smdodd}
196140467Simp
197140467Simpstatic int
19851829Smdoddan_detach_pci(device_t dev)
19951829Smdodd{
20051829Smdodd	struct an_softc		*sc = device_get_softc(dev);
20151829Smdodd	struct ifnet		*ifp = &sc->arpcom.ac_if;
20251829Smdodd
20351829Smdodd	an_stop(sc);
20451829Smdodd	ifmedia_removeall(&sc->an_ifmedia);
20551829Smdodd	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
20651829Smdodd	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
207140467Simp	an_release_resources(dev);
208140467Simp
209140467Simp	return (0);
21051829Smdodd}
21151829Smdodd
21251829Smdoddstatic device_method_t an_pci_methods[] = {
21351829Smdodd        /* Device interface */
21451829Smdodd        DEVMETHOD(device_probe,         an_probe_pci),
21551829Smdodd        DEVMETHOD(device_attach,        an_attach_pci),
21651829Smdodd	DEVMETHOD(device_detach,	an_detach_pci),
21751829Smdodd	DEVMETHOD(device_shutdown,	an_shutdown),
21851829Smdodd        { 0, 0 }
21951829Smdodd};
22051829Smdodd
22151829Smdoddstatic driver_t an_pci_driver = {
22251829Smdodd        "an",
22351829Smdodd        an_pci_methods,
22451829Smdodd        sizeof(struct an_softc),
22551829Smdodd};
22651829Smdodd
22751829Smdoddstatic devclass_t an_devclass;
22851829Smdodd
22951829SmdoddDRIVER_MODULE(if_an, pci, an_pci_driver, an_devclass, 0, 0);
23051829Smdodd