enp2611.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * IXP2400 MSF network device driver for the Radisys ENP2611
  3. * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
  4. * Dedicated to Marija Kulikova.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. */
  11. #include <linux/config.h>
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/etherdevice.h>
  16. #include <linux/init.h>
  17. #include <linux/moduleparam.h>
  18. #include <asm/arch/uengine.h>
  19. #include <asm/mach-types.h>
  20. #include <asm/io.h>
  21. #include "ixpdev.h"
  22. #include "caleb.h"
  23. #include "ixp2400-msf.h"
  24. #include "pm3386.h"
  25. /***********************************************************************
  26. * The Radisys ENP2611 is a PCI form factor board with three SFP GBIC
  27. * slots, connected via two PMC/Sierra 3386s and an SPI-3 bridge FPGA
  28. * to the IXP2400.
  29. *
  30. * +-------------+
  31. * SFP GBIC #0 ---+ | +---------+
  32. * | PM3386 #0 +-------+ |
  33. * SFP GBIC #1 ---+ | | "Caleb" | +---------+
  34. * +-------------+ | | | |
  35. * | SPI-3 +---------+ IXP2400 |
  36. * +-------------+ | bridge | | |
  37. * SFP GBIC #2 ---+ | | FPGA | +---------+
  38. * | PM3386 #1 +-------+ |
  39. * | | +---------+
  40. * +-------------+
  41. * ^ ^ ^
  42. * | 1.25Gbaud | 104MHz | 104MHz
  43. * | SERDES ea. | SPI-3 ea. | SPI-3
  44. *
  45. ***********************************************************************/
  46. static struct ixp2400_msf_parameters enp2611_msf_parameters =
  47. {
  48. .rx_mode = IXP2400_RX_MODE_UTOPIA_POS |
  49. IXP2400_RX_MODE_1x32 |
  50. IXP2400_RX_MODE_MPHY |
  51. IXP2400_RX_MODE_MPHY_32 |
  52. IXP2400_RX_MODE_MPHY_POLLED_STATUS |
  53. IXP2400_RX_MODE_MPHY_LEVEL3 |
  54. IXP2400_RX_MODE_RBUF_SIZE_64,
  55. .rxclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
  56. .rx_poll_ports = 3,
  57. .rx_channel_mode = {
  58. IXP2400_PORT_RX_MODE_MASTER |
  59. IXP2400_PORT_RX_MODE_POS_PHY |
  60. IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  61. IXP2400_PORT_RX_MODE_ODD_PARITY |
  62. IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  63. IXP2400_PORT_RX_MODE_MASTER |
  64. IXP2400_PORT_RX_MODE_POS_PHY |
  65. IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  66. IXP2400_PORT_RX_MODE_ODD_PARITY |
  67. IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  68. IXP2400_PORT_RX_MODE_MASTER |
  69. IXP2400_PORT_RX_MODE_POS_PHY |
  70. IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  71. IXP2400_PORT_RX_MODE_ODD_PARITY |
  72. IXP2400_PORT_RX_MODE_2_CYCLE_DECODE,
  73. IXP2400_PORT_RX_MODE_MASTER |
  74. IXP2400_PORT_RX_MODE_POS_PHY |
  75. IXP2400_PORT_RX_MODE_POS_PHY_L3 |
  76. IXP2400_PORT_RX_MODE_ODD_PARITY |
  77. IXP2400_PORT_RX_MODE_2_CYCLE_DECODE
  78. },
  79. .tx_mode = IXP2400_TX_MODE_UTOPIA_POS |
  80. IXP2400_TX_MODE_1x32 |
  81. IXP2400_TX_MODE_MPHY |
  82. IXP2400_TX_MODE_MPHY_32 |
  83. IXP2400_TX_MODE_MPHY_POLLED_STATUS |
  84. IXP2400_TX_MODE_MPHY_LEVEL3 |
  85. IXP2400_TX_MODE_TBUF_SIZE_64,
  86. .txclk01_multiplier = IXP2400_PLL_MULTIPLIER_16,
  87. .tx_poll_ports = 3,
  88. .tx_channel_mode = {
  89. IXP2400_PORT_TX_MODE_MASTER |
  90. IXP2400_PORT_TX_MODE_POS_PHY |
  91. IXP2400_PORT_TX_MODE_ODD_PARITY |
  92. IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
  93. IXP2400_PORT_TX_MODE_MASTER |
  94. IXP2400_PORT_TX_MODE_POS_PHY |
  95. IXP2400_PORT_TX_MODE_ODD_PARITY |
  96. IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
  97. IXP2400_PORT_TX_MODE_MASTER |
  98. IXP2400_PORT_TX_MODE_POS_PHY |
  99. IXP2400_PORT_TX_MODE_ODD_PARITY |
  100. IXP2400_PORT_TX_MODE_2_CYCLE_DECODE,
  101. IXP2400_PORT_TX_MODE_MASTER |
  102. IXP2400_PORT_TX_MODE_POS_PHY |
  103. IXP2400_PORT_TX_MODE_ODD_PARITY |
  104. IXP2400_PORT_TX_MODE_2_CYCLE_DECODE
  105. }
  106. };
  107. struct enp2611_ixpdev_priv
  108. {
  109. struct ixpdev_priv ixpdev_priv;
  110. struct net_device_stats stats;
  111. };
  112. static struct net_device *nds[3];
  113. static struct timer_list link_check_timer;
  114. static struct net_device_stats *enp2611_get_stats(struct net_device *dev)
  115. {
  116. struct enp2611_ixpdev_priv *ip = netdev_priv(dev);
  117. pm3386_get_stats(ip->ixpdev_priv.channel, &(ip->stats));
  118. return &(ip->stats);
  119. }
  120. /* @@@ Poll the SFP moddef0 line too. */
  121. /* @@@ Try to use the pm3386 DOOL interrupt as well. */
  122. static void enp2611_check_link_status(unsigned long __dummy)
  123. {
  124. int i;
  125. for (i = 0; i < 3; i++) {
  126. struct net_device *dev;
  127. int status;
  128. if (!netif_running(nds[i]))
  129. continue;
  130. dev = nds[i];
  131. status = pm3386_is_link_up(i);
  132. if (status && !netif_carrier_ok(nds[i])) {
  133. pm3386_enable_tx(i);
  134. caleb_enable_tx(i);
  135. netif_carrier_on(nds[i]);
  136. } else if (!status && netif_carrier_ok(nds[i])) {
  137. netif_carrier_off(nds[i]);
  138. caleb_disable_tx(i);
  139. pm3386_disable_tx(i);
  140. }
  141. }
  142. link_check_timer.expires = jiffies + HZ / 10;
  143. add_timer(&link_check_timer);
  144. }
  145. static void enp2611_set_port_admin_status(int port, int up)
  146. {
  147. if (up) {
  148. caleb_enable_rx(port);
  149. pm3386_enable_rx(port);
  150. } else {
  151. caleb_disable_tx(port);
  152. pm3386_disable_tx(port);
  153. pm3386_disable_rx(port);
  154. caleb_disable_rx(port);
  155. }
  156. }
  157. static int __init enp2611_init_module(void)
  158. {
  159. int i;
  160. if (!machine_is_enp2611())
  161. return -ENODEV;
  162. caleb_reset();
  163. pm3386_reset();
  164. for (i = 0; i < 3; i++) {
  165. nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
  166. if (nds[i] == NULL) {
  167. while (--i >= 0)
  168. free_netdev(nds[i]);
  169. return -ENOMEM;
  170. }
  171. SET_MODULE_OWNER(nds[i]);
  172. nds[i]->get_stats = enp2611_get_stats;
  173. pm3386_init_port(i);
  174. pm3386_get_mac(i, nds[i]->dev_addr);
  175. }
  176. ixp2400_msf_init(&enp2611_msf_parameters);
  177. if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) {
  178. for (i = 0; i < 3; i++)
  179. free_netdev(nds[i]);
  180. return -EINVAL;
  181. }
  182. init_timer(&link_check_timer);
  183. link_check_timer.function = enp2611_check_link_status;
  184. link_check_timer.expires = jiffies;
  185. add_timer(&link_check_timer);
  186. return 0;
  187. }
  188. static void __exit enp2611_cleanup_module(void)
  189. {
  190. int i;
  191. del_timer_sync(&link_check_timer);
  192. ixpdev_deinit();
  193. for (i = 0; i < 3; i++)
  194. free_netdev(nds[i]);
  195. }
  196. module_init(enp2611_init_module);
  197. module_exit(enp2611_cleanup_module);
  198. MODULE_LICENSE("GPL");