LCOV - code coverage report
Current view: top level - dev/pci - if_athn_pci.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 101 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_athn_pci.c,v 1.19 2017/01/12 16:32:28 stsp Exp $   */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
       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             :  * PCI front-end for Atheros 802.11a/g/n chipsets.
      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             : #include <machine/intr.h>
      37             : 
      38             : #include <net/if.h>
      39             : #include <net/if_media.h>
      40             : 
      41             : #include <netinet/in.h>
      42             : #include <netinet/if_ether.h>
      43             : 
      44             : #include <net80211/ieee80211_var.h>
      45             : #include <net80211/ieee80211_amrr.h>
      46             : #include <net80211/ieee80211_mira.h>
      47             : #include <net80211/ieee80211_radiotap.h>
      48             : 
      49             : #include <dev/ic/athnreg.h>
      50             : #include <dev/ic/athnvar.h>
      51             : 
      52             : #include <dev/pci/pcireg.h>
      53             : #include <dev/pci/pcivar.h>
      54             : #include <dev/pci/pcidevs.h>
      55             : 
      56             : #define PCI_SUBSYSID_ATHEROS_COEX2WIRE          0x309b
      57             : #define PCI_SUBSYSID_ATHEROS_COEX3WIRE_SA       0x30aa
      58             : #define PCI_SUBSYSID_ATHEROS_COEX3WIRE_DA       0x30ab
      59             : 
      60             : struct athn_pci_softc {
      61             :         struct athn_softc       sc_sc;
      62             : 
      63             :         /* PCI specific goo. */
      64             :         pci_chipset_tag_t       sc_pc;
      65             :         pcitag_t                sc_tag;
      66             :         void                    *sc_ih;
      67             :         bus_space_tag_t         sc_st;
      68             :         bus_space_handle_t      sc_sh;
      69             :         bus_size_t              sc_mapsize;
      70             :         int                     sc_cap_off;
      71             : };
      72             : 
      73             : int             athn_pci_match(struct device *, void *, void *);
      74             : void            athn_pci_attach(struct device *, struct device *, void *);
      75             : int             athn_pci_detach(struct device *, int);
      76             : int             athn_pci_activate(struct device *, int);
      77             : void            athn_pci_wakeup(struct athn_pci_softc *);
      78             : uint32_t        athn_pci_read(struct athn_softc *, uint32_t);
      79             : void            athn_pci_write(struct athn_softc *, uint32_t, uint32_t);
      80             : void            athn_pci_write_barrier(struct athn_softc *);
      81             : void            athn_pci_disable_aspm(struct athn_softc *);
      82             : 
      83             : struct cfattach athn_pci_ca = {
      84             :         sizeof (struct athn_pci_softc),
      85             :         athn_pci_match,
      86             :         athn_pci_attach,
      87             :         athn_pci_detach,
      88             :         athn_pci_activate
      89             : };
      90             : 
      91             : static const struct pci_matchid athn_pci_devices[] = {
      92             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 },
      93             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 },
      94             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 },
      95             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 },
      96             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 },
      97             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 },
      98             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 },
      99             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 },
     100             :         { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 }
     101             : };
     102             : 
     103             : int
     104           0 : athn_pci_match(struct device *parent, void *match, void *aux)
     105             : {
     106           0 :         return (pci_matchbyid(aux, athn_pci_devices,
     107             :             nitems(athn_pci_devices)));
     108             : }
     109             : 
     110             : void
     111           0 : athn_pci_attach(struct device *parent, struct device *self, void *aux)
     112             : {
     113           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)self;
     114           0 :         struct athn_softc *sc = &psc->sc_sc;
     115           0 :         struct pci_attach_args *pa = aux;
     116             :         const char *intrstr;
     117           0 :         pci_intr_handle_t ih;
     118             :         pcireg_t memtype, reg;
     119             :         pci_product_id_t subsysid;
     120             :         int error;
     121             : 
     122           0 :         sc->sc_dmat = pa->pa_dmat;
     123           0 :         psc->sc_pc = pa->pa_pc;
     124           0 :         psc->sc_tag = pa->pa_tag;
     125             : 
     126           0 :         sc->ops.read = athn_pci_read;
     127           0 :         sc->ops.write = athn_pci_write;
     128           0 :         sc->ops.write_barrier = athn_pci_write_barrier;
     129             : 
     130             :         /*
     131             :          * Get the offset of the PCI Express Capability Structure in PCI
     132             :          * Configuration Space (Linux hardcodes it as 0x60.)
     133             :          */
     134           0 :         error = pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
     135           0 :             &psc->sc_cap_off, NULL);
     136           0 :         if (error != 0) {       /* Found. */
     137           0 :                 sc->sc_disable_aspm = athn_pci_disable_aspm;
     138           0 :                 sc->flags |= ATHN_FLAG_PCIE;
     139           0 :         }
     140             :         /*
     141             :          * Noone knows why this shit is necessary but there are claims that
     142             :          * not doing this may cause very frequent PCI FATAL interrupts from
     143             :          * the card: http://bugzilla.kernel.org/show_bug.cgi?id=13483
     144             :          */
     145           0 :         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40);
     146           0 :         if (reg & 0xff00)
     147           0 :                 pci_conf_write(pa->pa_pc, pa->pa_tag, 0x40, reg & ~0xff00);
     148             : 
     149             :         /* Change latency timer; default value yields poor results. */
     150           0 :         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
     151           0 :         reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
     152           0 :         reg |= 168 << PCI_LATTIMER_SHIFT;
     153           0 :         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, reg);
     154             : 
     155             :         /* Determine if bluetooth is also supported (combo chip.) */
     156           0 :         reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
     157           0 :         subsysid = PCI_PRODUCT(reg);
     158           0 :         if (subsysid == PCI_SUBSYSID_ATHEROS_COEX3WIRE_SA ||
     159           0 :             subsysid == PCI_SUBSYSID_ATHEROS_COEX3WIRE_DA)
     160           0 :                 sc->flags |= ATHN_FLAG_BTCOEX3WIRE;
     161           0 :         else if (subsysid == PCI_SUBSYSID_ATHEROS_COEX2WIRE)
     162           0 :                 sc->flags |= ATHN_FLAG_BTCOEX2WIRE;
     163             : 
     164             :         /* Map control/status registers. */
     165           0 :         memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
     166           0 :         error = pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &psc->sc_st,
     167           0 :             &psc->sc_sh, NULL, &psc->sc_mapsize, 0);
     168           0 :         if (error != 0) {
     169           0 :                 printf(": can't map mem space\n");
     170           0 :                 return;
     171             :         }
     172             : 
     173           0 :         if (pci_intr_map(pa, &ih) != 0) {
     174           0 :                 printf(": can't map interrupt\n");
     175           0 :                 return;
     176             :         }
     177           0 :         intrstr = pci_intr_string(psc->sc_pc, ih);
     178           0 :         psc->sc_ih = pci_intr_establish(psc->sc_pc, ih, IPL_NET,
     179           0 :             athn_intr, sc, sc->sc_dev.dv_xname);
     180           0 :         if (psc->sc_ih == NULL) {
     181           0 :                 printf(": can't establish interrupt");
     182           0 :                 if (intrstr != NULL)
     183           0 :                         printf(" at %s", intrstr);
     184           0 :                 printf("\n");
     185           0 :                 return;
     186             :         }
     187           0 :         printf(": %s\n", intrstr);
     188             : 
     189           0 :         athn_attach(sc);
     190           0 : }
     191             : 
     192             : int
     193           0 : athn_pci_detach(struct device *self, int flags)
     194             : {
     195           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)self;
     196           0 :         struct athn_softc *sc = &psc->sc_sc;
     197             : 
     198           0 :         if (psc->sc_ih != NULL) {
     199           0 :                 athn_detach(sc);
     200           0 :                 pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
     201           0 :         }
     202           0 :         if (psc->sc_mapsize > 0)
     203           0 :                 bus_space_unmap(psc->sc_st, psc->sc_sh, psc->sc_mapsize);
     204             : 
     205           0 :         return (0);
     206             : }
     207             : 
     208             : int
     209           0 : athn_pci_activate(struct device *self, int act)
     210             : {
     211           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)self;
     212           0 :         struct athn_softc *sc = &psc->sc_sc;
     213             : 
     214           0 :         switch (act) {
     215             :         case DVACT_SUSPEND:
     216           0 :                 athn_suspend(sc);
     217           0 :                 break;
     218             :         case DVACT_WAKEUP:
     219           0 :                 athn_pci_wakeup(psc);
     220           0 :                 break;
     221             :         }
     222             : 
     223           0 :         return (0);
     224             : }
     225             : 
     226             : void
     227           0 : athn_pci_wakeup(struct athn_pci_softc *psc)
     228             : {
     229           0 :         struct athn_softc *sc = &psc->sc_sc;
     230             :         pcireg_t reg;
     231             :         int s;
     232             : 
     233           0 :         reg = pci_conf_read(psc->sc_pc, psc->sc_tag, 0x40);
     234           0 :         if (reg & 0xff00)
     235           0 :                 pci_conf_write(psc->sc_pc, psc->sc_tag, 0x40, reg & ~0xff00);
     236             : 
     237           0 :         s = splnet();
     238           0 :         athn_wakeup(sc);
     239           0 :         splx(s);
     240           0 : }
     241             : 
     242             : uint32_t
     243           0 : athn_pci_read(struct athn_softc *sc, uint32_t addr)
     244             : {
     245           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)sc;
     246             : 
     247           0 :         return (bus_space_read_4(psc->sc_st, psc->sc_sh, addr));
     248             : }
     249             : 
     250             : void
     251           0 : athn_pci_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
     252             : {
     253           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)sc;
     254             : 
     255           0 :         bus_space_write_4(psc->sc_st, psc->sc_sh, addr, val);
     256           0 : }
     257             : 
     258             : void
     259           0 : athn_pci_write_barrier(struct athn_softc *sc)
     260             : {
     261           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)sc;
     262             : 
     263           0 :         bus_space_barrier(psc->sc_st, psc->sc_sh, 0, psc->sc_mapsize,
     264             :             BUS_SPACE_BARRIER_WRITE);
     265           0 : }
     266             : 
     267             : void
     268           0 : athn_pci_disable_aspm(struct athn_softc *sc)
     269             : {
     270           0 :         struct athn_pci_softc *psc = (struct athn_pci_softc *)sc;
     271             :         pcireg_t reg;
     272             : 
     273             :         /* Disable PCIe Active State Power Management (ASPM). */
     274           0 :         reg = pci_conf_read(psc->sc_pc, psc->sc_tag,
     275           0 :             psc->sc_cap_off + PCI_PCIE_LCSR);
     276           0 :         reg &= ~(PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1);
     277           0 :         pci_conf_write(psc->sc_pc, psc->sc_tag,
     278           0 :             psc->sc_cap_off + PCI_PCIE_LCSR, reg);
     279           0 : }

Generated by: LCOV version 1.13