if_athn_cardbus.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /* $OpenBSD: if_athn_cardbus.c,v 1.13 2011/01/08 10:02:32 damien Exp $ */
  2. /*-
  3. * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /*
  18. * CardBus front-end for Atheros 802.11a/g/n chipsets.
  19. */
  20. #include "bpfilter.h"
  21. #include <sys/param.h>
  22. #include <sys/sockio.h>
  23. #include <sys/mbuf.h>
  24. #include <sys/kernel.h>
  25. #include <sys/socket.h>
  26. #include <sys/systm.h>
  27. #include <sys/malloc.h>
  28. #include <sys/timeout.h>
  29. #include <sys/device.h>
  30. #include <machine/bus.h>
  31. #include <machine/intr.h>
  32. #include <net/if.h>
  33. #include <net/if_dl.h>
  34. #include <net/if_media.h>
  35. #include <netinet/in.h>
  36. #include <netinet/if_ether.h>
  37. #include <net80211/ieee80211_var.h>
  38. #include <net80211/ieee80211_amrr.h>
  39. #include <net80211/ieee80211_radiotap.h>
  40. #include <dev/ic/athnreg.h>
  41. #include <dev/ic/athnvar.h>
  42. #include <dev/pci/pcireg.h>
  43. #include <dev/pci/pcivar.h>
  44. #include <dev/pci/pcidevs.h>
  45. #include <dev/cardbus/cardbusvar.h>
  46. struct athn_cardbus_softc {
  47. struct athn_softc sc_sc;
  48. /* CardBus specific goo. */
  49. cardbus_devfunc_t sc_ct;
  50. pcitag_t sc_tag;
  51. void *sc_ih;
  52. bus_space_tag_t sc_st;
  53. bus_space_handle_t sc_sh;
  54. bus_size_t sc_mapsize;
  55. pcireg_t sc_bar_val;
  56. int sc_intrline;
  57. pci_chipset_tag_t sc_pc;
  58. };
  59. int athn_cardbus_match(struct device *, void *, void *);
  60. void athn_cardbus_attach(struct device *, struct device *, void *);
  61. int athn_cardbus_detach(struct device *, int);
  62. int athn_cardbus_enable(struct athn_softc *);
  63. void athn_cardbus_disable(struct athn_softc *);
  64. void athn_cardbus_power(struct athn_softc *, int);
  65. void athn_cardbus_setup(struct athn_cardbus_softc *);
  66. uint32_t athn_cardbus_read(struct athn_softc *, uint32_t);
  67. void athn_cardbus_write(struct athn_softc *, uint32_t, uint32_t);
  68. void athn_cardbus_write_barrier(struct athn_softc *);
  69. struct cfattach athn_cardbus_ca = {
  70. sizeof (struct athn_cardbus_softc),
  71. athn_cardbus_match,
  72. athn_cardbus_attach,
  73. athn_cardbus_detach
  74. };
  75. static const struct pci_matchid athn_cardbus_devices[] = {
  76. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 },
  77. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 },
  78. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 },
  79. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 },
  80. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 },
  81. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 },
  82. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 },
  83. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 },
  84. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 },
  85. { PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9300 }
  86. };
  87. int
  88. athn_cardbus_match(struct device *parent, void *match, void *aux)
  89. {
  90. return (cardbus_matchbyid(aux, athn_cardbus_devices,
  91. nitems(athn_cardbus_devices)));
  92. }
  93. void
  94. athn_cardbus_attach(struct device *parent, struct device *self, void *aux)
  95. {
  96. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
  97. struct athn_softc *sc = &csc->sc_sc;
  98. struct cardbus_attach_args *ca = aux;
  99. cardbus_devfunc_t ct = ca->ca_ct;
  100. bus_addr_t base;
  101. int error;
  102. sc->sc_dmat = ca->ca_dmat;
  103. csc->sc_ct = ct;
  104. csc->sc_tag = ca->ca_tag;
  105. csc->sc_intrline = ca->ca_intrline;
  106. csc->sc_pc = ca->ca_pc;
  107. /* Power management hooks. */
  108. sc->sc_enable = athn_cardbus_enable;
  109. sc->sc_disable = athn_cardbus_disable;
  110. sc->sc_power = athn_cardbus_power;
  111. sc->ops.read = athn_cardbus_read;
  112. sc->ops.write = athn_cardbus_write;
  113. sc->ops.write_barrier = athn_cardbus_write_barrier;
  114. /* Map control/status registers. */
  115. error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG,
  116. PCI_MAPREG_TYPE_MEM, 0, &csc->sc_st, &csc->sc_sh, &base,
  117. &csc->sc_mapsize);
  118. if (error != 0) {
  119. printf(": can't map mem space\n");
  120. return;
  121. }
  122. csc->sc_bar_val = base | PCI_MAPREG_TYPE_MEM;
  123. /* Set up the PCI configuration registers. */
  124. athn_cardbus_setup(csc);
  125. printf(": irq %d\n", csc->sc_intrline);
  126. athn_attach(sc);
  127. Cardbus_function_disable(ct);
  128. }
  129. int
  130. athn_cardbus_detach(struct device *self, int flags)
  131. {
  132. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)self;
  133. struct athn_softc *sc = &csc->sc_sc;
  134. cardbus_devfunc_t ct = csc->sc_ct;
  135. cardbus_chipset_tag_t cc = ct->ct_cc;
  136. cardbus_function_tag_t cf = ct->ct_cf;
  137. athn_detach(sc);
  138. /* Unhook the interrupt handler. */
  139. if (csc->sc_ih != NULL)
  140. cardbus_intr_disestablish(cc, cf, csc->sc_ih);
  141. /* Release bus space and close window. */
  142. Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_st, csc->sc_sh,
  143. csc->sc_mapsize);
  144. return (0);
  145. }
  146. int
  147. athn_cardbus_enable(struct athn_softc *sc)
  148. {
  149. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  150. cardbus_devfunc_t ct = csc->sc_ct;
  151. cardbus_chipset_tag_t cc = ct->ct_cc;
  152. cardbus_function_tag_t cf = ct->ct_cf;
  153. /* Power on the socket. */
  154. Cardbus_function_enable(ct);
  155. /* Setup the PCI configuration registers. */
  156. athn_cardbus_setup(csc);
  157. /* Map and establish the interrupt handler. */
  158. csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET,
  159. athn_intr, sc, sc->sc_dev.dv_xname);
  160. if (csc->sc_ih == NULL) {
  161. printf("%s: could not establish interrupt at %d\n",
  162. sc->sc_dev.dv_xname, csc->sc_intrline);
  163. Cardbus_function_disable(ct);
  164. return (1);
  165. }
  166. return (0);
  167. }
  168. void
  169. athn_cardbus_disable(struct athn_softc *sc)
  170. {
  171. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  172. cardbus_devfunc_t ct = csc->sc_ct;
  173. cardbus_chipset_tag_t cc = ct->ct_cc;
  174. cardbus_function_tag_t cf = ct->ct_cf;
  175. /* Unhook the interrupt handler. */
  176. cardbus_intr_disestablish(cc, cf, csc->sc_ih);
  177. csc->sc_ih = NULL;
  178. /* Power down the socket. */
  179. Cardbus_function_disable(ct);
  180. }
  181. void
  182. athn_cardbus_power(struct athn_softc *sc, int why)
  183. {
  184. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  185. if (why == DVACT_RESUME) {
  186. /* Restore the PCI configuration registers. */
  187. athn_cardbus_setup(csc);
  188. }
  189. }
  190. void
  191. athn_cardbus_setup(struct athn_cardbus_softc *csc)
  192. {
  193. cardbus_devfunc_t ct = csc->sc_ct;
  194. cardbus_chipset_tag_t cc = ct->ct_cc;
  195. pci_chipset_tag_t pc = csc->sc_pc;
  196. cardbus_function_tag_t cf = ct->ct_cf;
  197. pcireg_t reg;
  198. /* Program the BAR. */
  199. pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG,
  200. csc->sc_bar_val);
  201. /* Make sure the right access type is on the cardbus bridge. */
  202. (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE);
  203. (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
  204. /* Enable the appropriate bits in the PCI CSR. */
  205. reg = pci_conf_read(pc, csc->sc_tag,
  206. PCI_COMMAND_STATUS_REG);
  207. reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE;
  208. pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG,
  209. reg);
  210. /*
  211. * Noone knows why this shit is necessary but there are claims that
  212. * not doing this may cause very frequent PCI FATAL interrupts from
  213. * the card: http://bugzilla.kernel.org/show_bug.cgi?id=13483
  214. */
  215. reg = pci_conf_read(pc, csc->sc_tag, 0x40);
  216. if (reg & 0xff00)
  217. pci_conf_write(pc, csc->sc_tag, 0x40, reg & ~0xff00);
  218. /* Change latency timer; default value yields poor results. */
  219. reg = pci_conf_read(pc, csc->sc_tag, PCI_BHLC_REG);
  220. reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
  221. reg |= 168 << PCI_LATTIMER_SHIFT;
  222. pci_conf_write(pc, csc->sc_tag, PCI_BHLC_REG, reg);
  223. }
  224. uint32_t
  225. athn_cardbus_read(struct athn_softc *sc, uint32_t addr)
  226. {
  227. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  228. return (bus_space_read_4(csc->sc_st, csc->sc_sh, addr));
  229. }
  230. void
  231. athn_cardbus_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
  232. {
  233. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  234. bus_space_write_4(csc->sc_st, csc->sc_sh, addr, val);
  235. }
  236. void
  237. athn_cardbus_write_barrier(struct athn_softc *sc)
  238. {
  239. struct athn_cardbus_softc *csc = (struct athn_cardbus_softc *)sc;
  240. bus_space_barrier(csc->sc_st, csc->sc_sh, 0, csc->sc_mapsize,
  241. BUS_SPACE_BARRIER_WRITE);
  242. }