enp2611.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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/hardware/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. dev = nds[i];
  129. status = pm3386_is_link_up(i);
  130. if (status && !netif_carrier_ok(dev)) {
  131. /* @@@ Should report autonegotiation status. */
  132. printk(KERN_INFO "%s: NIC Link is Up\n", dev->name);
  133. pm3386_enable_tx(i);
  134. caleb_enable_tx(i);
  135. netif_carrier_on(dev);
  136. } else if (!status && netif_carrier_ok(dev)) {
  137. printk(KERN_INFO "%s: NIC Link is Down\n", dev->name);
  138. netif_carrier_off(dev);
  139. caleb_disable_tx(i);
  140. pm3386_disable_tx(i);
  141. }
  142. }
  143. link_check_timer.expires = jiffies + HZ / 10;
  144. add_timer(&link_check_timer);
  145. }
  146. static void enp2611_set_port_admin_status(int port, int up)
  147. {
  148. if (up) {
  149. caleb_enable_rx(port);
  150. pm3386_set_carrier(port, 1);
  151. pm3386_enable_rx(port);
  152. } else {
  153. caleb_disable_tx(port);
  154. pm3386_disable_tx(port);
  155. /* @@@ Flush out pending packets. */
  156. pm3386_set_carrier(port, 0);
  157. pm3386_disable_rx(port);
  158. caleb_disable_rx(port);
  159. }
  160. }
  161. static int __init enp2611_init_module(void)
  162. {
  163. int i;
  164. if (!machine_is_enp2611())
  165. return -ENODEV;
  166. caleb_reset();
  167. pm3386_reset();
  168. for (i = 0; i < 3; i++) {
  169. nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
  170. if (nds[i] == NULL) {
  171. while (--i >= 0)
  172. free_netdev(nds[i]);
  173. return -ENOMEM;
  174. }
  175. SET_MODULE_OWNER(nds[i]);
  176. nds[i]->get_stats = enp2611_get_stats;
  177. pm3386_init_port(i);
  178. pm3386_get_mac(i, nds[i]->dev_addr);
  179. }
  180. ixp2400_msf_init(&enp2611_msf_parameters);
  181. if (ixpdev_init(3, nds, enp2611_set_port_admin_status)) {
  182. for (i = 0; i < 3; i++)
  183. free_netdev(nds[i]);
  184. return -EINVAL;
  185. }
  186. init_timer(&link_check_timer);
  187. link_check_timer.function = enp2611_check_link_status;
  188. link_check_timer.expires = jiffies;
  189. add_timer(&link_check_timer);
  190. return 0;
  191. }
  192. static void __exit enp2611_cleanup_module(void)
  193. {
  194. int i;
  195. del_timer_sync(&link_check_timer);
  196. ixpdev_deinit();
  197. for (i = 0; i < 3; i++)
  198. free_netdev(nds[i]);
  199. }
  200. module_init(enp2611_init_module);
  201. module_exit(enp2611_cleanup_module);
  202. MODULE_LICENSE("GPL");