PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/sys/dev/pci/if_art.c

https://bitbucket.org/kmv/aeriebsd-src
C | 447 lines | 336 code | 58 blank | 53 comment | 74 complexity | 642a9cf2031409f07200d628bf5dd244 MD5 | raw file
  1. /*
  2. * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
  3. * Written by: Claudio Jeker <jeker@accoom.net>
  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. #include <sys/param.h>
  18. #include <sys/device.h>
  19. #include <sys/proc.h>
  20. #include <sys/socket.h>
  21. #include <sys/sockio.h>
  22. #include <sys/syslog.h>
  23. #include <sys/systm.h>
  24. #include <machine/bus.h>
  25. #include <net/if.h>
  26. #include <net/if_media.h>
  27. #include <net/if_sppp.h>
  28. #include <dev/pci/musyccvar.h>
  29. #include <dev/pci/if_art.h>
  30. #define ART_E1_MASK 0xffffffff
  31. #define ART_T1_MASK 0x01fffffe
  32. int art_match(struct device *, void *, void *);
  33. void art_softc_attach(struct device *, struct device *, void *);
  34. int art_ioctl(struct ifnet *, u_long, caddr_t);
  35. int art_ifm_change(struct ifnet *);
  36. void art_ifm_status(struct ifnet *, struct ifmediareq *);
  37. int art_ifm_options(struct ifnet *, struct channel_softc *, u_int);
  38. void art_onesec(void *);
  39. void art_linkstate(void *);
  40. u_int32_t art_mask_tsmap(u_int, u_int32_t);
  41. struct cfattach art_ca = {
  42. sizeof(struct art_softc), art_match, art_softc_attach
  43. };
  44. struct cfdriver art_cd = {
  45. NULL, "art", DV_DULL
  46. };
  47. int
  48. art_match(struct device *parent, void *match, void *aux)
  49. {
  50. struct musycc_attach_args *ma = aux;
  51. if (ma->ma_type == MUSYCC_FRAMER_BT8370)
  52. return (1);
  53. return (0);
  54. }
  55. /*
  56. * used for the one second timer
  57. */
  58. extern int hz;
  59. void
  60. art_softc_attach(struct device *parent, struct device *self, void *aux)
  61. {
  62. struct art_softc *sc = (struct art_softc *)self;
  63. struct musycc_softc *psc = (struct musycc_softc *)parent;
  64. struct musycc_attach_args *ma = aux;
  65. printf(" \"%s\"", ma->ma_product);
  66. if (ebus_attach_device(&sc->art_ebus, psc, ma->ma_base,
  67. ma->ma_size) != 0) {
  68. printf(": could not map framer\n");
  69. return;
  70. }
  71. /* set basic values */
  72. sc->art_port = ma->ma_port;
  73. sc->art_slot = ma->ma_slot;
  74. sc->art_gnum = ma->ma_gnum;
  75. sc->art_type = ma->ma_flags & 0x03;
  76. sc->art_channel = musycc_channel_create(self->dv_xname, 1);
  77. if (sc->art_channel == NULL) {
  78. printf(": could not alloc channel descriptor\n");
  79. return;
  80. }
  81. if (musycc_channel_attach(psc, sc->art_channel, self, sc->art_gnum) ==
  82. -1) {
  83. printf(": unable to attach to hdlc controller\n");
  84. return;
  85. }
  86. ifmedia_init(&sc->art_ifm, 0, art_ifm_change, art_ifm_status);
  87. ifmedia_add(&sc->art_ifm,
  88. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, 0, 0), 0, NULL);
  89. ifmedia_add(&sc->art_ifm,
  90. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, 0, 0), 0, NULL);
  91. ifmedia_add(&sc->art_ifm,
  92. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, 0, 0), 0, NULL);
  93. ifmedia_add(&sc->art_ifm,
  94. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, 0, 0), 0, NULL);
  95. ifmedia_add(&sc->art_ifm,
  96. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, 0, 0), 0, NULL);
  97. ifmedia_add(&sc->art_ifm,
  98. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_MASTER, 0), 0, NULL);
  99. ifmedia_add(&sc->art_ifm,
  100. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_MASTER, 0), 0, NULL);
  101. ifmedia_add(&sc->art_ifm,
  102. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_MASTER, 0), 0, NULL);
  103. ifmedia_add(&sc->art_ifm,
  104. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_MASTER, 0), 0, NULL);
  105. ifmedia_add(&sc->art_ifm,
  106. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_MASTER, 0),
  107. 0, NULL);
  108. ifmedia_add(&sc->art_ifm,
  109. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP, 0), 0, NULL);
  110. ifmedia_add(&sc->art_ifm,
  111. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP, 0), 0, NULL);
  112. ifmedia_add(&sc->art_ifm,
  113. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP, 0), 0, NULL);
  114. ifmedia_add(&sc->art_ifm,
  115. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP, 0), 0, NULL);
  116. ifmedia_add(&sc->art_ifm,
  117. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP, 0), 0,
  118. NULL);
  119. ifmedia_add(&sc->art_ifm,
  120. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
  121. 0, NULL);
  122. ifmedia_add(&sc->art_ifm,
  123. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
  124. 0, NULL);
  125. ifmedia_add(&sc->art_ifm,
  126. IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP | IFM_TDM_MASTER,
  127. 0), 0, NULL);
  128. ifmedia_add(&sc->art_ifm,
  129. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP |
  130. IFM_TDM_MASTER, 0), 0, NULL);
  131. ifmedia_add(&sc->art_ifm,
  132. IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP |
  133. IFM_TDM_MASTER, 0), 0, NULL);
  134. printf("\n");
  135. if (bt8370_reset(sc) != 0)
  136. return;
  137. /* Initialize timeout for statistics update. */
  138. timeout_set(&sc->art_onesec, art_onesec, sc);
  139. ifmedia_set(&sc->art_ifm, IFM_TDM|IFM_TDM_E1_G704_CRC4);
  140. sc->art_media = sc->art_ifm.ifm_media;
  141. bt8370_set_frame_mode(sc, sc->art_type, IFM_TDM_E1_G704_CRC4, 0);
  142. musycc_attach_sppp(sc->art_channel, art_ioctl);
  143. /* Set linkstate hook to track link state changes done by sppp. */
  144. sc->art_linkstatehook = hook_establish(
  145. sc->art_channel->cc_ifp->if_linkstatehooks, 0, art_linkstate, sc);
  146. /* Schedule the timeout one second from now. */
  147. timeout_add(&sc->art_onesec, hz);
  148. }
  149. /* interface ioctl */
  150. int
  151. art_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  152. {
  153. struct ifreq *ifr = (struct ifreq*) data;
  154. struct channel_softc *cc = ifp->if_softc;
  155. struct art_softc *ac = (struct art_softc *)cc->cc_parent;
  156. u_int32_t tsmap;
  157. int s, rv = 0;
  158. s = splnet();
  159. switch (command) {
  160. case SIOCSIFADDR:
  161. if ((rv = musycc_init_channel(cc, ac->art_slot)))
  162. break;
  163. rv = sppp_ioctl(ifp, command, data);
  164. break;
  165. case SIOCSIFTIMESLOT:
  166. if ((rv = suser(curproc, 0)) != 0)
  167. break;
  168. rv = copyin(ifr->ifr_data, &tsmap, sizeof(tsmap));
  169. if (rv)
  170. break;
  171. if (art_mask_tsmap(IFM_SUBTYPE(ac->art_media), tsmap) !=
  172. tsmap) {
  173. rv = EINVAL;
  174. break;
  175. }
  176. if (ac->art_type == ART_SBI_SINGLE &&
  177. (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
  178. IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
  179. /*
  180. * need to adjust timeslot mask for T1 on single port
  181. * cards. There timeslot 0-23 are usable not 1-24
  182. */
  183. tsmap >>= 1;
  184. cc->cc_tslots = tsmap;
  185. rv = musycc_init_channel(cc, ac->art_slot);
  186. break;
  187. case SIOCGIFTIMESLOT:
  188. tsmap = cc->cc_tslots;
  189. if (ac->art_type == ART_SBI_SINGLE &&
  190. (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
  191. IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
  192. tsmap <<= 1;
  193. rv = copyout(&tsmap, ifr->ifr_data, sizeof(tsmap));
  194. break;
  195. case SIOCSIFFLAGS:
  196. /*
  197. * If interface is marked up and not running, then start it.
  198. * If it is marked down and running, stop it.
  199. */
  200. if (ifr->ifr_flags & IFF_UP && cc->cc_state != CHAN_RUNNING) {
  201. if ((rv = musycc_init_channel(cc, ac->art_slot)))
  202. break;
  203. } else if ((ifr->ifr_flags & IFF_UP) == 0 &&
  204. cc->cc_state == CHAN_RUNNING)
  205. musycc_stop_channel(cc);
  206. rv = sppp_ioctl(ifp, command, data);
  207. break;
  208. case SIOCSIFMEDIA:
  209. case SIOCGIFMEDIA:
  210. if (ac != NULL)
  211. rv = ifmedia_ioctl(ifp, ifr, &ac->art_ifm, command);
  212. else
  213. rv = EINVAL;
  214. break;
  215. default:
  216. rv = sppp_ioctl(ifp, command, data);
  217. break;
  218. }
  219. splx(s);
  220. return (rv);
  221. }
  222. int
  223. art_ifm_change(struct ifnet *ifp)
  224. {
  225. struct channel_softc *cc = ifp->if_softc;
  226. struct art_softc *ac = (struct art_softc *)cc->cc_parent;
  227. struct ifmedia *ifm = &ac->art_ifm;
  228. u_int64_t baudrate;
  229. int rv, s;
  230. ACCOOM_PRINTF(2, ("%s: art_ifm_change %08x\n", ifp->if_xname,
  231. ifm->ifm_media));
  232. if (IFM_TYPE(ifm->ifm_media) != IFM_TDM)
  233. return (EINVAL);
  234. /* OPTIONS (controller mode hdlc, ppp, eoe) */
  235. if ((rv = art_ifm_options(ifp, cc, IFM_OPTIONS(ifm->ifm_media))) != 0)
  236. return (rv);
  237. /* SUBTYPE (framing mode T1/E1) + MODE (clocking master/slave) */
  238. if (IFM_SUBTYPE(ifm->ifm_media) != IFM_SUBTYPE(ac->art_media) ||
  239. IFM_MODE(ifm->ifm_media) != IFM_MODE(ac->art_media)) {
  240. ACCOOM_PRINTF(0, ("%s: art_ifm_change type %d mode %x\n",
  241. ifp->if_xname, IFM_SUBTYPE(ifm->ifm_media),
  242. IFM_MODE(ifm->ifm_media)));
  243. bt8370_set_frame_mode(ac, ac->art_type,
  244. IFM_SUBTYPE(ifm->ifm_media), IFM_MODE(ifm->ifm_media));
  245. if (IFM_SUBTYPE(ifm->ifm_media) != IFM_SUBTYPE(ac->art_media)) {
  246. /* adjust timeslot map on media change */
  247. cc->cc_tslots = art_mask_tsmap(
  248. IFM_SUBTYPE(ifm->ifm_media), cc->cc_tslots);
  249. if (ac->art_type == ART_SBI_SINGLE &&
  250. (IFM_SUBTYPE(ifm->ifm_media) == IFM_TDM_T1 ||
  251. IFM_SUBTYPE(ifm->ifm_media) == IFM_TDM_T1_AMI) &&
  252. (IFM_SUBTYPE(ac->art_media) != IFM_TDM_T1 &&
  253. IFM_SUBTYPE(ac->art_media) != IFM_TDM_T1_AMI))
  254. /*
  255. * need to adjust timeslot mask for T1 on
  256. * single port cards. There timeslot 0-23 are
  257. * usable not 1-24
  258. */
  259. cc->cc_tslots >>= 1;
  260. else if (ac->art_type == ART_SBI_SINGLE &&
  261. (IFM_SUBTYPE(ifm->ifm_media) != IFM_TDM_T1 &&
  262. IFM_SUBTYPE(ifm->ifm_media) != IFM_TDM_T1_AMI) &&
  263. (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
  264. IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
  265. /* undo the last adjustment */
  266. cc->cc_tslots <<= 1;
  267. }
  268. /* re-init the card */
  269. if ((rv = musycc_init_channel(cc, ac->art_slot)))
  270. return (rv);
  271. }
  272. baudrate = ifmedia_baudrate(ac->art_media);
  273. if (baudrate != ifp->if_baudrate) {
  274. ifp->if_baudrate = baudrate;
  275. s = splsoftnet();
  276. if_link_state_change(ifp);
  277. splx(s);
  278. }
  279. ac->art_media = ifm->ifm_media;
  280. return (0);
  281. }
  282. void
  283. art_ifm_status(struct ifnet *ifp, struct ifmediareq *ifmreq)
  284. {
  285. struct art_softc *ac;
  286. ac = (struct art_softc *)
  287. ((struct channel_softc *)ifp->if_softc)->cc_parent;
  288. ifmreq->ifm_status = IFM_AVALID;
  289. if (LINK_STATE_IS_UP(ifp->if_link_state))
  290. ifmreq->ifm_status |= IFM_ACTIVE;
  291. ifmreq->ifm_active = ac->art_media;
  292. return;
  293. }
  294. int
  295. art_ifm_options(struct ifnet *ifp, struct channel_softc *cc, u_int options)
  296. {
  297. struct art_softc *ac = (struct art_softc *)cc->cc_parent;
  298. u_int flags = cc->cc_ppp.pp_flags;
  299. int rv;
  300. if (options == IFM_TDM_PPP) {
  301. flags &= ~PP_CISCO;
  302. flags |= PP_KEEPALIVE;
  303. } else if (options == 0) {
  304. flags |= PP_CISCO;
  305. flags |= PP_KEEPALIVE;
  306. } else {
  307. ACCOOM_PRINTF(0, ("%s: Unsupported ifmedia options\n",
  308. ifp->if_xname));
  309. return (EINVAL);
  310. }
  311. if (flags != cc->cc_ppp.pp_flags) {
  312. musycc_stop_channel(cc);
  313. cc->cc_ppp.pp_flags = flags;
  314. if ((rv = musycc_init_channel(cc, ac->art_slot)))
  315. return (rv);
  316. return (sppp_ioctl(ifp, SIOCSIFFLAGS, NULL));
  317. }
  318. return (0);
  319. }
  320. void
  321. art_onesec(void *arg)
  322. {
  323. struct art_softc *ac = arg;
  324. struct ifnet *ifp = ac->art_channel->cc_ifp;
  325. struct sppp *ppp = &ac->art_channel->cc_ppp;
  326. int s, rv, link_state;
  327. rv = bt8370_link_status(ac);
  328. switch (rv) {
  329. case 1:
  330. link_state = LINK_STATE_UP;
  331. /* set green led */
  332. ebus_set_led(ac->art_channel, 1, MUSYCC_LED_GREEN);
  333. break;
  334. case 0:
  335. link_state = LINK_STATE_DOWN;
  336. /* set green led and red led as well */
  337. ebus_set_led(ac->art_channel, 1,
  338. MUSYCC_LED_GREEN | MUSYCC_LED_RED);
  339. break;
  340. default:
  341. link_state = LINK_STATE_DOWN;
  342. /* turn green led off */
  343. ebus_set_led(ac->art_channel, 0, MUSYCC_LED_GREEN);
  344. break;
  345. }
  346. if (link_state != ifp->if_link_state) {
  347. s = splsoftnet();
  348. if (LINK_STATE_IS_UP(link_state))
  349. ppp->pp_up(ppp);
  350. else
  351. ppp->pp_down(ppp);
  352. splx(s);
  353. }
  354. /*
  355. * run musycc onesec job
  356. */
  357. musycc_tick(ac->art_channel);
  358. /*
  359. * Schedule another timeout one second from now.
  360. */
  361. timeout_add(&ac->art_onesec, hz);
  362. }
  363. void
  364. art_linkstate(void *arg)
  365. {
  366. struct art_softc *ac = arg;
  367. struct ifnet *ifp = ac->art_channel->cc_ifp;
  368. if (LINK_STATE_IS_UP(ifp->if_link_state))
  369. /* turn red led off */
  370. ebus_set_led(ac->art_channel, 0, MUSYCC_LED_RED);
  371. else
  372. /* turn red led on */
  373. ebus_set_led(ac->art_channel, 1, MUSYCC_LED_RED);
  374. }
  375. u_int32_t
  376. art_mask_tsmap(u_int mode, u_int32_t tsmap)
  377. {
  378. switch (mode) {
  379. case IFM_TDM_E1:
  380. case IFM_TDM_E1_G704:
  381. case IFM_TDM_E1_G704_CRC4:
  382. return (tsmap & ART_E1_MASK);
  383. case IFM_TDM_T1_AMI:
  384. case IFM_TDM_T1:
  385. return (tsmap & ART_T1_MASK);
  386. default:
  387. return (tsmap);
  388. }
  389. }