enp2611.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. static struct net_device *nds[3];
  107. static struct timer_list link_check_timer;
  108. /* @@@ Poll the SFP moddef0 line too. */
  109. /* @@@ Try to use the pm3386 DOOL interrupt as well. */
  110. static void enp2611_check_link_status(unsigned long __dummy)
  111. {
  112. int i;
  113. for (i = 0; i < 3; i++) {
  114. struct net_device *dev;
  115. int status;
  116. dev = nds[i];
  117. if (dev == NULL)
  118. continue;
  119. status = pm3386_is_link_up(i);
  120. if (status && !netif_carrier_ok(dev)) {
  121. /* @@@ Should report autonegotiation status. */
  122. printk(KERN_INFO "%s: NIC Link is Up\n", dev->name);
  123. pm3386_enable_tx(i);
  124. caleb_enable_tx(i);
  125. netif_carrier_on(dev);
  126. } else if (!status && netif_carrier_ok(dev)) {
  127. printk(KERN_INFO "%s: NIC Link is Down\n", dev->name);
  128. netif_carrier_off(dev);
  129. caleb_disable_tx(i);
  130. pm3386_disable_tx(i);
  131. }
  132. }
  133. link_check_timer.expires = jiffies + HZ / 10;
  134. add_timer(&link_check_timer);
  135. }
  136. static void enp2611_set_port_admin_status(int port, int up)
  137. {
  138. if (up) {
  139. caleb_enable_rx(port);
  140. pm3386_set_carrier(port, 1);
  141. pm3386_enable_rx(port);
  142. } else {
  143. caleb_disable_tx(port);
  144. pm3386_disable_tx(port);
  145. /* @@@ Flush out pending packets. */
  146. pm3386_set_carrier(port, 0);
  147. pm3386_disable_rx(port);
  148. caleb_disable_rx(port);
  149. }
  150. }
  151. static int __init enp2611_init_module(void)
  152. {
  153. int ports;
  154. int i;
  155. if (!machine_is_enp2611())
  156. return -ENODEV;
  157. caleb_reset();
  158. pm3386_reset();
  159. ports = pm3386_port_count();
  160. for (i = 0; i < ports; i++) {
  161. nds[i] = ixpdev_alloc(i, sizeof(struct ixpdev_priv));
  162. if (nds[i] == NULL) {
  163. while (--i >= 0)
  164. free_netdev(nds[i]);
  165. return -ENOMEM;
  166. }
  167. pm3386_init_port(i);
  168. pm3386_get_mac(i, nds[i]->dev_addr);
  169. }
  170. ixp2400_msf_init(&enp2611_msf_parameters);
  171. if (ixpdev_init(ports, nds, enp2611_set_port_admin_status)) {
  172. for (i = 0; i < ports; i++)
  173. if (nds[i])
  174. free_netdev(nds[i]);
  175. return -EINVAL;
  176. }
  177. init_timer(&link_check_timer);
  178. link_check_timer.function = enp2611_check_link_status;
  179. link_check_timer.expires = jiffies;
  180. add_timer(&link_check_timer);
  181. return 0;
  182. }
  183. static void __exit enp2611_cleanup_module(void)
  184. {
  185. int i;
  186. del_timer_sync(&link_check_timer);
  187. ixpdev_deinit();
  188. for (i = 0; i < 3; i++)
  189. free_netdev(nds[i]);
  190. }
  191. module_init(enp2611_init_module);
  192. module_exit(enp2611_cleanup_module);
  193. MODULE_LICENSE("GPL");