enp2611.c 6.4 KB

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