fixed.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * drivers/net/phy/fixed.c
  3. *
  4. * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode.
  5. *
  6. * Author: Vitaly Bordug
  7. *
  8. * Copyright (c) 2006 MontaVista Software, Inc.
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by the
  12. * Free Software Foundation; either version 2 of the License, or (at your
  13. * option) any later version.
  14. *
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/string.h>
  18. #include <linux/errno.h>
  19. #include <linux/unistd.h>
  20. #include <linux/slab.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/init.h>
  23. #include <linux/delay.h>
  24. #include <linux/netdevice.h>
  25. #include <linux/etherdevice.h>
  26. #include <linux/skbuff.h>
  27. #include <linux/spinlock.h>
  28. #include <linux/mm.h>
  29. #include <linux/module.h>
  30. #include <linux/mii.h>
  31. #include <linux/ethtool.h>
  32. #include <linux/phy.h>
  33. #include <linux/phy_fixed.h>
  34. #include <asm/io.h>
  35. #include <asm/irq.h>
  36. #include <asm/uaccess.h>
  37. /* we need to track the allocated pointers in order to free them on exit */
  38. static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
  39. /*-----------------------------------------------------------------------------
  40. * If something weird is required to be done with link/speed,
  41. * network driver is able to assign a function to implement this.
  42. * May be useful for PHY's that need to be software-driven.
  43. *-----------------------------------------------------------------------------*/
  44. int fixed_mdio_set_link_update(struct phy_device *phydev,
  45. int (*link_update) (struct net_device *,
  46. struct fixed_phy_status *))
  47. {
  48. struct fixed_info *fixed;
  49. if (link_update == NULL)
  50. return -EINVAL;
  51. if (phydev) {
  52. if (phydev->bus) {
  53. fixed = phydev->bus->priv;
  54. fixed->link_update = link_update;
  55. return 0;
  56. }
  57. }
  58. return -EINVAL;
  59. }
  60. EXPORT_SYMBOL(fixed_mdio_set_link_update);
  61. struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
  62. {
  63. if (phydev_ind >= MAX_PHY_AMNT)
  64. return NULL;
  65. return fixed_phy_ptrs[phydev_ind];
  66. }
  67. EXPORT_SYMBOL(fixed_mdio_get_phydev);
  68. /*-----------------------------------------------------------------------------
  69. * This is used for updating internal mii regs from the status
  70. *-----------------------------------------------------------------------------*/
  71. #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
  72. static int fixed_mdio_update_regs(struct fixed_info *fixed)
  73. {
  74. u16 *regs = fixed->regs;
  75. u16 bmsr = 0;
  76. u16 bmcr = 0;
  77. if (!regs) {
  78. printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
  79. return -EINVAL;
  80. }
  81. if (fixed->phy_status.link)
  82. bmsr |= BMSR_LSTATUS;
  83. if (fixed->phy_status.duplex) {
  84. bmcr |= BMCR_FULLDPLX;
  85. switch (fixed->phy_status.speed) {
  86. case 100:
  87. bmsr |= BMSR_100FULL;
  88. bmcr |= BMCR_SPEED100;
  89. break;
  90. case 10:
  91. bmsr |= BMSR_10FULL;
  92. break;
  93. }
  94. } else {
  95. switch (fixed->phy_status.speed) {
  96. case 100:
  97. bmsr |= BMSR_100HALF;
  98. bmcr |= BMCR_SPEED100;
  99. break;
  100. case 10:
  101. bmsr |= BMSR_100HALF;
  102. break;
  103. }
  104. }
  105. regs[MII_BMCR] = bmcr;
  106. regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */
  107. return 0;
  108. }
  109. static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
  110. {
  111. struct fixed_info *fixed = bus->priv;
  112. /* if user has registered link update callback, use it */
  113. if (fixed->phydev)
  114. if (fixed->phydev->attached_dev) {
  115. if (fixed->link_update) {
  116. fixed->link_update(fixed->phydev->attached_dev,
  117. &fixed->phy_status);
  118. fixed_mdio_update_regs(fixed);
  119. }
  120. }
  121. if ((unsigned int)location >= fixed->regs_num)
  122. return -1;
  123. return fixed->regs[location];
  124. }
  125. static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
  126. u16 val)
  127. {
  128. /* do nothing for now */
  129. return 0;
  130. }
  131. static int fixed_mii_reset(struct mii_bus *bus)
  132. {
  133. /*nothing here - no way/need to reset it */
  134. return 0;
  135. }
  136. #endif
  137. static int fixed_config_aneg(struct phy_device *phydev)
  138. {
  139. /* :TODO:03/13/2006 09:45:37 PM::
  140. The full autoneg funcionality can be emulated,
  141. but no need to have anything here for now
  142. */
  143. return 0;
  144. }
  145. /*-----------------------------------------------------------------------------
  146. * the manual bind will do the magic - with phy_id_mask == 0
  147. * match will never return true...
  148. *-----------------------------------------------------------------------------*/
  149. static struct phy_driver fixed_mdio_driver = {
  150. .name = "Fixed PHY",
  151. #ifdef CONFIG_FIXED_MII_1000_FDX
  152. .features = PHY_GBIT_FEATURES,
  153. #else
  154. .features = PHY_BASIC_FEATURES,
  155. #endif
  156. .config_aneg = fixed_config_aneg,
  157. .read_status = genphy_read_status,
  158. .driver = { .owner = THIS_MODULE, },
  159. };
  160. static void fixed_mdio_release(struct device *dev)
  161. {
  162. struct phy_device *phydev = container_of(dev, struct phy_device, dev);
  163. struct mii_bus *bus = phydev->bus;
  164. struct fixed_info *fixed = bus->priv;
  165. kfree(phydev);
  166. kfree(bus->dev);
  167. kfree(bus);
  168. kfree(fixed->regs);
  169. kfree(fixed);
  170. }
  171. /*-----------------------------------------------------------------------------
  172. * This func is used to create all the necessary stuff, bind
  173. * the fixed phy driver and register all it on the mdio_bus_type.
  174. * speed is either 10 or 100 or 1000, duplex is boolean.
  175. * number is used to create multiple fixed PHYs, so that several devices can
  176. * utilize them simultaneously.
  177. *
  178. * The device on mdio bus will look like [bus_id]:[phy_id],
  179. * bus_id = number
  180. * phy_id = speed+duplex.
  181. *-----------------------------------------------------------------------------*/
  182. #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
  183. struct fixed_info *fixed_mdio_register_device(
  184. int bus_id, int speed, int duplex, u8 phy_id)
  185. {
  186. struct mii_bus *new_bus;
  187. struct fixed_info *fixed;
  188. struct phy_device *phydev;
  189. int err;
  190. struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
  191. if (dev == NULL)
  192. goto err_dev_alloc;
  193. new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
  194. if (new_bus == NULL)
  195. goto err_bus_alloc;
  196. fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
  197. if (fixed == NULL)
  198. goto err_fixed_alloc;
  199. fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
  200. if (NULL == fixed->regs)
  201. goto err_fixed_regs_alloc;
  202. fixed->regs_num = MII_REGS_NUM;
  203. fixed->phy_status.speed = speed;
  204. fixed->phy_status.duplex = duplex;
  205. fixed->phy_status.link = 1;
  206. new_bus->name = "Fixed MII Bus";
  207. new_bus->read = &fixed_mii_read;
  208. new_bus->write = &fixed_mii_write;
  209. new_bus->reset = &fixed_mii_reset;
  210. /*set up workspace */
  211. fixed_mdio_update_regs(fixed);
  212. new_bus->priv = fixed;
  213. new_bus->dev = dev;
  214. dev_set_drvdata(dev, new_bus);
  215. /* create phy_device and register it on the mdio bus */
  216. phydev = phy_device_create(new_bus, 0, 0);
  217. if (phydev == NULL)
  218. goto err_phy_dev_create;
  219. /*
  220. * Put the phydev pointer into the fixed pack so that bus read/write
  221. * code could be able to access for instance attached netdev. Well it
  222. * doesn't have to do so, only in case of utilizing user-specified
  223. * link-update...
  224. */
  225. fixed->phydev = phydev;
  226. phydev->speed = speed;
  227. phydev->duplex = duplex;
  228. phydev->irq = PHY_IGNORE_INTERRUPT;
  229. phydev->dev.bus = &mdio_bus_type;
  230. snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
  231. PHY_ID_FMT, bus_id, phy_id);
  232. phydev->bus = new_bus;
  233. phydev->dev.driver = &fixed_mdio_driver.driver;
  234. phydev->dev.release = fixed_mdio_release;
  235. err = phydev->dev.driver->probe(&phydev->dev);
  236. if (err < 0) {
  237. printk(KERN_ERR "Phy %s: problems with fixed driver\n",
  238. phydev->dev.bus_id);
  239. goto err_out;
  240. }
  241. err = device_register(&phydev->dev);
  242. if (err) {
  243. printk(KERN_ERR "Phy %s failed to register\n",
  244. phydev->dev.bus_id);
  245. goto err_out;
  246. }
  247. //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
  248. return fixed;
  249. err_out:
  250. kfree(phydev);
  251. err_phy_dev_create:
  252. kfree(fixed->regs);
  253. err_fixed_regs_alloc:
  254. kfree(fixed);
  255. err_fixed_alloc:
  256. kfree(new_bus);
  257. err_bus_alloc:
  258. kfree(dev);
  259. err_dev_alloc:
  260. return NULL;
  261. }
  262. #endif
  263. MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
  264. MODULE_AUTHOR("Vitaly Bordug");
  265. MODULE_LICENSE("GPL");
  266. static int __init fixed_init(void)
  267. {
  268. int cnt = 0;
  269. int i;
  270. /* register on the bus... Not expected to be matched
  271. * with anything there...
  272. *
  273. */
  274. phy_driver_register(&fixed_mdio_driver);
  275. /* We will create several mdio devices here, and will bound the upper
  276. * driver to them.
  277. *
  278. * Then the external software can lookup the phy bus by searching
  279. * for 0:101, to be connected to the virtual 100M Fdx phy.
  280. *
  281. * In case several virtual PHYs required, the bus_id will be in form
  282. * [num]:[duplex]+[speed], which make it able even to define
  283. * driver-specific link control callback, if for instance PHY is
  284. * completely SW-driven.
  285. */
  286. for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
  287. #ifdef CONFIG_FIXED_MII_1000_FDX
  288. fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
  289. #endif
  290. #ifdef CONFIG_FIXED_MII_100_FDX
  291. fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
  292. #endif
  293. #ifdef CONFIG_FIXED_MII_10_FDX
  294. fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
  295. #endif
  296. }
  297. return 0;
  298. }
  299. static void __exit fixed_exit(void)
  300. {
  301. int i;
  302. phy_driver_unregister(&fixed_mdio_driver);
  303. for (i=0; i < MAX_PHY_AMNT; i++)
  304. if ( fixed_phy_ptrs[i] )
  305. device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
  306. }
  307. module_init(fixed_init);
  308. module_exit(fixed_exit);