if_pgt_cardbus.c revision 1.18
1/* $OpenBSD: if_pgt_cardbus.c,v 1.18 2015/12/11 16:07:01 mpi Exp $ */ 2 3/* 4 * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* 20 * CardBus front-end for the PrismGT 21 */ 22 23#include "bpfilter.h" 24 25#include <sys/param.h> 26#include <sys/sockio.h> 27#include <sys/mbuf.h> 28#include <sys/kernel.h> 29#include <sys/socket.h> 30#include <sys/systm.h> 31#include <sys/malloc.h> 32#include <sys/timeout.h> 33#include <sys/device.h> 34 35#include <machine/bus.h> 36 37#include <net/if.h> 38#include <net/if_media.h> 39 40#include <netinet/in.h> 41#include <netinet/if_ether.h> 42 43#include <net80211/ieee80211_var.h> 44#include <net80211/ieee80211_radiotap.h> 45 46#include <dev/ic/pgtreg.h> 47#include <dev/ic/pgtvar.h> 48 49#include <dev/pci/pcireg.h> 50#include <dev/pci/pcivar.h> 51#include <dev/pci/pcidevs.h> 52 53#include <dev/cardbus/cardbusvar.h> 54 55struct pgt_cardbus_softc { 56 struct pgt_softc sc_pgt; 57 cardbus_devfunc_t sc_ct; 58 pcitag_t sc_tag; 59 int sc_intrline; 60 61 void *sc_ih; 62 bus_size_t sc_mapsize; 63 pcireg_t sc_bar0_val; 64 pci_chipset_tag_t sc_pc; 65}; 66 67int pgt_cardbus_match(struct device *, void *, void *); 68void pgt_cardbus_attach(struct device *, struct device *, void *); 69int pgt_cardbus_detach(struct device *, int); 70int pgt_cardbus_enable(struct pgt_softc *); 71void pgt_cardbus_disable(struct pgt_softc *); 72void pgt_cardbus_power(struct pgt_softc *, int); 73void pgt_cardbus_setup(struct pgt_cardbus_softc *); 74 75struct cfattach pgt_cardbus_ca = { 76 sizeof(struct pgt_cardbus_softc), pgt_cardbus_match, pgt_cardbus_attach, 77 pgt_cardbus_detach 78}; 79 80const struct pci_matchid pgt_cardbus_devices[] = { 81 { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3877 }, 82 { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3890 }, 83 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3CRWE154G72 } 84}; 85 86int 87pgt_cardbus_match(struct device *parent, void *match, void *aux) 88{ 89 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 90 pgt_cardbus_devices, 91 sizeof(pgt_cardbus_devices) / sizeof(pgt_cardbus_devices[0]))); 92} 93 94void 95pgt_cardbus_attach(struct device *parent, struct device *self, void *aux) 96{ 97 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)self; 98 struct pgt_softc *sc = &csc->sc_pgt; 99 struct cardbus_attach_args *ca = aux; 100 cardbus_devfunc_t ct = ca->ca_ct; 101 bus_addr_t base; 102 int error; 103 104 sc->sc_dmat = ca->ca_dmat; 105 csc->sc_ct = ct; 106 csc->sc_tag = ca->ca_tag; 107 csc->sc_intrline = ca->ca_intrline; 108 csc->sc_pc = ca->ca_pc; 109 110 /* power management hooks */ 111 sc->sc_enable = pgt_cardbus_enable; 112 sc->sc_disable = pgt_cardbus_disable; 113 sc->sc_power = pgt_cardbus_power; 114 115 /* remember chipset */ 116 if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_INTERSIL_ISL3877) 117 sc->sc_flags |= SC_ISL3877; 118 119 /* map control / status registers */ 120 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 121 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, 122 &sc->sc_iotag, &sc->sc_iohandle, &base, &csc->sc_mapsize); 123 if (error != 0) { 124 printf(": can't map mem space\n"); 125 return; 126 } 127 csc->sc_bar0_val = base | PCI_MAPREG_TYPE_MEM; 128 129 /* disable all interrupts */ 130 bus_space_write_4(sc->sc_iotag, sc->sc_iohandle, PGT_REG_INT_EN, 0); 131 (void)bus_space_read_4(sc->sc_iotag, sc->sc_iohandle, PGT_REG_INT_EN); 132 DELAY(PGT_WRITEIO_DELAY); 133 134 /* set up the PCI configuration registers */ 135 pgt_cardbus_setup(csc); 136 137 printf(": irq %d\n", csc->sc_intrline); 138 139 config_mountroot(self, pgt_attach); 140} 141 142int 143pgt_cardbus_detach(struct device *self, int flags) 144{ 145 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)self; 146 struct pgt_softc *sc = &csc->sc_pgt; 147 cardbus_devfunc_t ct = csc->sc_ct; 148 cardbus_chipset_tag_t cc = ct->ct_cc; 149 cardbus_function_tag_t cf = ct->ct_cf; 150 int error; 151 152 error = pgt_detach(sc); 153 if (error != 0) 154 return (error); 155 156 /* unhook the interrupt handler */ 157 if (csc->sc_ih != NULL) { 158 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 159 csc->sc_ih = NULL; 160 } 161 162 /* release bus space and close window */ 163 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, 164 sc->sc_iotag, sc->sc_iohandle, csc->sc_mapsize); 165 166 return (0); 167} 168 169int 170pgt_cardbus_enable(struct pgt_softc *sc) 171{ 172 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)sc; 173 cardbus_devfunc_t ct = csc->sc_ct; 174 cardbus_chipset_tag_t cc = ct->ct_cc; 175 cardbus_function_tag_t cf = ct->ct_cf; 176 177 /* power on the socket */ 178 Cardbus_function_enable(ct); 179 180 /* setup the PCI configuration registers */ 181 pgt_cardbus_setup(csc); 182 183 /* map and establish the interrupt handler */ 184 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 185 pgt_intr, sc, sc->sc_dev.dv_xname); 186 if (csc->sc_ih == NULL) { 187 printf("%s: could not establish interrupt at %d\n", 188 sc->sc_dev.dv_xname, csc->sc_intrline); 189 Cardbus_function_disable(ct); 190 return (1); 191 } 192 193 return (0); 194} 195 196void 197pgt_cardbus_disable(struct pgt_softc *sc) 198{ 199 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)sc; 200 cardbus_devfunc_t ct = csc->sc_ct; 201 cardbus_chipset_tag_t cc = ct->ct_cc; 202 cardbus_function_tag_t cf = ct->ct_cf; 203 204 /* unhook the interrupt handler */ 205 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 206 csc->sc_ih = NULL; 207 208 /* power down the socket */ 209 Cardbus_function_disable(ct); 210} 211 212void 213pgt_cardbus_power(struct pgt_softc *sc, int why) 214{ 215 if (why == DVACT_RESUME) 216 if (sc->sc_enable != NULL) 217 (*sc->sc_enable)(sc); 218 if (why == DVACT_SUSPEND) 219 if (sc->sc_disable != NULL) 220 (*sc->sc_disable)(sc); 221} 222 223void 224pgt_cardbus_setup(struct pgt_cardbus_softc *csc) 225{ 226 cardbus_devfunc_t ct = csc->sc_ct; 227 cardbus_chipset_tag_t cc = ct->ct_cc; 228 pci_chipset_tag_t pc = csc->sc_pc; 229 cardbus_function_tag_t cf = ct->ct_cf; 230 pcireg_t reg; 231 232 /* program the BAR */ 233 pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG, 234 csc->sc_bar0_val); 235 236 /* make sure the right access type is on the cardbus bridge */ 237 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 238 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 239 240 /* enable the appropriate bits in the PCI CSR */ 241 reg = pci_conf_read(pc, csc->sc_tag, 242 PCI_COMMAND_STATUS_REG); 243 reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 244 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, 245 reg); 246} 247