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