diff options
author | Vitaly Bordug <vitb@kernel.crashing.org> | 2007-12-06 17:51:22 -0500 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2008-01-23 20:33:58 -0500 |
commit | a79d8e93d300adb84cccc38ac396cfb118c238ad (patch) | |
tree | d3c6e163a697029b0c7a14c745318f4f58a69445 | |
parent | 9b6d19dd1d87fcca43ebadfad2f50cee07fbef5e (diff) |
phy/fixed.c: rework to not duplicate PHY layer functionality
With that patch fixed.c now fully emulates MDIO bus, thus no need
to duplicate PHY layer functionality. That, in turn, drastically
simplifies the code, and drops down line count.
As an additional bonus, now there is no need to register MDIO bus
for each PHY, all emulated PHYs placed on the platform fixed MDIO bus.
There is also no more need to pre-allocate PHYs via .config option,
this is all now handled dynamically.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
Acked-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r-- | drivers/net/phy/Kconfig | 32 | ||||
-rw-r--r-- | drivers/net/phy/fixed.c | 445 | ||||
-rw-r--r-- | include/linux/phy_fixed.h | 51 |
3 files changed, 195 insertions, 333 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 54b2ba996640..7fe03ce774b1 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -61,34 +61,12 @@ config ICPLUS_PHY | |||
61 | Currently supports the IP175C PHY. | 61 | Currently supports the IP175C PHY. |
62 | 62 | ||
63 | config FIXED_PHY | 63 | config FIXED_PHY |
64 | tristate "Drivers for PHY emulation on fixed speed/link" | 64 | bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" |
65 | ---help--- | 65 | ---help--- |
66 | Adds the driver to PHY layer to cover the boards that do not have any PHY bound, | 66 | Adds the platform "fixed" MDIO Bus to cover the boards that use |
67 | but with the ability to manipulate the speed/link in software. The relevant MII | 67 | PHYs that are not connected to the real MDIO bus. |
68 | speed/duplex parameters could be effectively handled in a user-specified function. | 68 | |
69 | Currently tested with mpc866ads. | 69 | Currently tested with mpc866ads and mpc8349e-mitx. |
70 | |||
71 | config FIXED_MII_10_FDX | ||
72 | bool "Emulation for 10M Fdx fixed PHY behavior" | ||
73 | depends on FIXED_PHY | ||
74 | |||
75 | config FIXED_MII_100_FDX | ||
76 | bool "Emulation for 100M Fdx fixed PHY behavior" | ||
77 | depends on FIXED_PHY | ||
78 | |||
79 | config FIXED_MII_1000_FDX | ||
80 | bool "Emulation for 1000M Fdx fixed PHY behavior" | ||
81 | depends on FIXED_PHY | ||
82 | |||
83 | config FIXED_MII_AMNT | ||
84 | int "Number of emulated PHYs to allocate " | ||
85 | depends on FIXED_PHY | ||
86 | default "1" | ||
87 | ---help--- | ||
88 | Sometimes it is required to have several independent emulated | ||
89 | PHYs on the bus (in case of multi-eth but phy-less HW for instance). | ||
90 | This control will have specified number allocated for each fixed | ||
91 | PHY type enabled. | ||
92 | 70 | ||
93 | config MDIO_BITBANG | 71 | config MDIO_BITBANG |
94 | tristate "Support for bitbanged MDIO buses" | 72 | tristate "Support for bitbanged MDIO buses" |
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 56191822fa26..73b6d39ef6b0 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c | |||
@@ -1,362 +1,253 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/net/phy/fixed.c | 2 | * Fixed MDIO bus (MDIO bus emulation with fixed PHYs) |
3 | * | 3 | * |
4 | * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode. | 4 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> |
5 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
5 | * | 6 | * |
6 | * Author: Vitaly Bordug | 7 | * Copyright (c) 2006-2007 MontaVista Software, Inc. |
7 | * | ||
8 | * Copyright (c) 2006 MontaVista Software, Inc. | ||
9 | * | 8 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 9 | * 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 | 10 | * 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 | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 12 | * option) any later version. |
14 | * | ||
15 | */ | 13 | */ |
14 | |||
16 | #include <linux/kernel.h> | 15 | #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> | 16 | #include <linux/module.h> |
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/list.h> | ||
30 | #include <linux/mii.h> | 19 | #include <linux/mii.h> |
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/phy.h> | 20 | #include <linux/phy.h> |
33 | #include <linux/phy_fixed.h> | 21 | #include <linux/phy_fixed.h> |
34 | 22 | ||
35 | #include <asm/io.h> | 23 | #define MII_REGS_NUM 29 |
36 | #include <asm/irq.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | 24 | ||
39 | /* we need to track the allocated pointers in order to free them on exit */ | 25 | struct fixed_mdio_bus { |
40 | static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT]; | 26 | int irqs[PHY_MAX_ADDR]; |
41 | 27 | struct mii_bus mii_bus; | |
42 | /*----------------------------------------------------------------------------- | 28 | struct list_head phys; |
43 | * If something weird is required to be done with link/speed, | 29 | }; |
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 | *-----------------------------------------------------------------------------*/ | ||
47 | int 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 | |||
66 | EXPORT_SYMBOL(fixed_mdio_set_link_update); | ||
67 | 30 | ||
68 | struct fixed_info *fixed_mdio_get_phydev (int phydev_ind) | 31 | struct fixed_phy { |
69 | { | 32 | int id; |
70 | if (phydev_ind >= MAX_PHY_AMNT) | 33 | u16 regs[MII_REGS_NUM]; |
71 | return NULL; | 34 | struct phy_device *phydev; |
72 | return fixed_phy_ptrs[phydev_ind]; | 35 | struct fixed_phy_status status; |
73 | } | 36 | int (*link_update)(struct net_device *, struct fixed_phy_status *); |
37 | struct list_head node; | ||
38 | }; | ||
74 | 39 | ||
75 | EXPORT_SYMBOL(fixed_mdio_get_phydev); | 40 | static struct platform_device *pdev; |
41 | static struct fixed_mdio_bus platform_fmb = { | ||
42 | .phys = LIST_HEAD_INIT(platform_fmb.phys), | ||
43 | }; | ||
76 | 44 | ||
77 | /*----------------------------------------------------------------------------- | 45 | static int fixed_phy_update_regs(struct fixed_phy *fp) |
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) | ||
81 | static int fixed_mdio_update_regs(struct fixed_info *fixed) | ||
82 | { | 46 | { |
83 | u16 *regs = fixed->regs; | 47 | u16 bmsr = BMSR_ANEGCAPABLE; |
84 | u16 bmsr = 0; | ||
85 | u16 bmcr = 0; | 48 | u16 bmcr = 0; |
49 | u16 lpagb = 0; | ||
50 | u16 lpa = 0; | ||
86 | 51 | ||
87 | if (!regs) { | 52 | if (fp->status.duplex) { |
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; | 53 | bmcr |= BMCR_FULLDPLX; |
97 | 54 | ||
98 | switch (fixed->phy_status.speed) { | 55 | switch (fp->status.speed) { |
56 | case 1000: | ||
57 | bmsr |= BMSR_ESTATEN; | ||
58 | bmcr |= BMCR_SPEED1000; | ||
59 | lpagb |= LPA_1000FULL; | ||
60 | break; | ||
99 | case 100: | 61 | case 100: |
100 | bmsr |= BMSR_100FULL; | 62 | bmsr |= BMSR_100FULL; |
101 | bmcr |= BMCR_SPEED100; | 63 | bmcr |= BMCR_SPEED100; |
64 | lpa |= LPA_100FULL; | ||
102 | break; | 65 | break; |
103 | |||
104 | case 10: | 66 | case 10: |
105 | bmsr |= BMSR_10FULL; | 67 | bmsr |= BMSR_10FULL; |
68 | lpa |= LPA_10FULL; | ||
106 | break; | 69 | break; |
70 | default: | ||
71 | printk(KERN_WARNING "fixed phy: unknown speed\n"); | ||
72 | return -EINVAL; | ||
107 | } | 73 | } |
108 | } else { | 74 | } else { |
109 | switch (fixed->phy_status.speed) { | 75 | switch (fp->status.speed) { |
76 | case 1000: | ||
77 | bmsr |= BMSR_ESTATEN; | ||
78 | bmcr |= BMCR_SPEED1000; | ||
79 | lpagb |= LPA_1000HALF; | ||
80 | break; | ||
110 | case 100: | 81 | case 100: |
111 | bmsr |= BMSR_100HALF; | 82 | bmsr |= BMSR_100HALF; |
112 | bmcr |= BMCR_SPEED100; | 83 | bmcr |= BMCR_SPEED100; |
84 | lpa |= LPA_100HALF; | ||
113 | break; | 85 | break; |
114 | |||
115 | case 10: | 86 | case 10: |
116 | bmsr |= BMSR_100HALF; | 87 | bmsr |= BMSR_10HALF; |
88 | lpa |= LPA_10HALF; | ||
117 | break; | 89 | break; |
90 | default: | ||
91 | printk(KERN_WARNING "fixed phy: unknown speed\n"); | ||
92 | return -EINVAL; | ||
118 | } | 93 | } |
119 | } | 94 | } |
120 | 95 | ||
121 | regs[MII_BMCR] = bmcr; | 96 | if (fp->status.link) |
122 | regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */ | 97 | bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; |
98 | |||
99 | if (fp->status.pause) | ||
100 | lpa |= LPA_PAUSE_CAP; | ||
101 | |||
102 | if (fp->status.asym_pause) | ||
103 | lpa |= LPA_PAUSE_ASYM; | ||
104 | |||
105 | fp->regs[MII_PHYSID1] = fp->id >> 16; | ||
106 | fp->regs[MII_PHYSID2] = fp->id; | ||
107 | |||
108 | fp->regs[MII_BMSR] = bmsr; | ||
109 | fp->regs[MII_BMCR] = bmcr; | ||
110 | fp->regs[MII_LPA] = lpa; | ||
111 | fp->regs[MII_STAT1000] = lpagb; | ||
123 | 112 | ||
124 | return 0; | 113 | return 0; |
125 | } | 114 | } |
126 | 115 | ||
127 | static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) | 116 | static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num) |
128 | { | 117 | { |
129 | struct fixed_info *fixed = bus->priv; | 118 | struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus, |
130 | 119 | mii_bus); | |
131 | /* if user has registered link update callback, use it */ | 120 | struct fixed_phy *fp; |
132 | if (fixed->phydev) | 121 | |
133 | if (fixed->phydev->attached_dev) { | 122 | if (reg_num >= MII_REGS_NUM) |
134 | if (fixed->link_update) { | 123 | return -1; |
135 | fixed->link_update(fixed->phydev->attached_dev, | 124 | |
136 | &fixed->phy_status); | 125 | list_for_each_entry(fp, &fmb->phys, node) { |
137 | fixed_mdio_update_regs(fixed); | 126 | if (fp->id == phy_id) { |
127 | /* Issue callback if user registered it. */ | ||
128 | if (fp->link_update) { | ||
129 | fp->link_update(fp->phydev->attached_dev, | ||
130 | &fp->status); | ||
131 | fixed_phy_update_regs(fp); | ||
138 | } | 132 | } |
133 | return fp->regs[reg_num]; | ||
139 | } | 134 | } |
135 | } | ||
140 | 136 | ||
141 | if ((unsigned int)location >= fixed->regs_num) | 137 | return 0xFFFF; |
142 | return -1; | ||
143 | return fixed->regs[location]; | ||
144 | } | 138 | } |
145 | 139 | ||
146 | static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, | 140 | static int fixed_mdio_write(struct mii_bus *bus, int phy_id, int reg_num, |
147 | u16 val) | 141 | u16 val) |
148 | { | 142 | { |
149 | /* do nothing for now */ | ||
150 | return 0; | 143 | return 0; |
151 | } | 144 | } |
152 | 145 | ||
153 | static int fixed_mii_reset(struct mii_bus *bus) | 146 | /* |
147 | * If something weird is required to be done with link/speed, | ||
148 | * network driver is able to assign a function to implement this. | ||
149 | * May be useful for PHY's that need to be software-driven. | ||
150 | */ | ||
151 | int fixed_phy_set_link_update(struct phy_device *phydev, | ||
152 | int (*link_update)(struct net_device *, | ||
153 | struct fixed_phy_status *)) | ||
154 | { | 154 | { |
155 | /*nothing here - no way/need to reset it */ | 155 | struct fixed_mdio_bus *fmb = &platform_fmb; |
156 | return 0; | 156 | struct fixed_phy *fp; |
157 | } | ||
158 | #endif | ||
159 | 157 | ||
160 | static int fixed_config_aneg(struct phy_device *phydev) | 158 | if (!link_update || !phydev || !phydev->bus) |
161 | { | 159 | return -EINVAL; |
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 | 160 | ||
169 | /*----------------------------------------------------------------------------- | 161 | list_for_each_entry(fp, &fmb->phys, node) { |
170 | * the manual bind will do the magic - with phy_id_mask == 0 | 162 | if (fp->id == phydev->phy_id) { |
171 | * match will never return true... | 163 | fp->link_update = link_update; |
172 | *-----------------------------------------------------------------------------*/ | 164 | fp->phydev = phydev; |
173 | static struct phy_driver fixed_mdio_driver = { | 165 | return 0; |
174 | .name = "Fixed PHY", | 166 | } |
175 | #ifdef CONFIG_FIXED_MII_1000_FDX | 167 | } |
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 | 168 | ||
185 | static void fixed_mdio_release(struct device *dev) | 169 | return -ENOENT; |
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 | } | 170 | } |
171 | EXPORT_SYMBOL_GPL(fixed_phy_set_link_update); | ||
197 | 172 | ||
198 | /*----------------------------------------------------------------------------- | 173 | int fixed_phy_add(unsigned int irq, int phy_id, |
199 | * This func is used to create all the necessary stuff, bind | 174 | struct fixed_phy_status *status) |
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) | ||
210 | struct fixed_info *fixed_mdio_register_device( | ||
211 | int bus_id, int speed, int duplex, u8 phy_id) | ||
212 | { | 175 | { |
213 | struct mii_bus *new_bus; | 176 | int ret; |
214 | struct fixed_info *fixed; | 177 | struct fixed_mdio_bus *fmb = &platform_fmb; |
215 | struct phy_device *phydev; | 178 | struct fixed_phy *fp; |
216 | int err; | ||
217 | 179 | ||
218 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 180 | fp = kzalloc(sizeof(*fp), GFP_KERNEL); |
181 | if (!fp) | ||
182 | return -ENOMEM; | ||
219 | 183 | ||
220 | if (dev == NULL) | 184 | memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM); |
221 | goto err_dev_alloc; | ||
222 | 185 | ||
223 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | 186 | fmb->irqs[phy_id] = irq; |
224 | 187 | ||
225 | if (new_bus == NULL) | 188 | fp->id = phy_id; |
226 | goto err_bus_alloc; | 189 | fp->status = *status; |
227 | 190 | ||
228 | fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); | 191 | ret = fixed_phy_update_regs(fp); |
192 | if (ret) | ||
193 | goto err_regs; | ||
229 | 194 | ||
230 | if (fixed == NULL) | 195 | list_add_tail(&fp->node, &fmb->phys); |
231 | goto err_fixed_alloc; | ||
232 | 196 | ||
233 | fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL); | 197 | return 0; |
234 | if (NULL == fixed->regs) | ||
235 | goto err_fixed_regs_alloc; | ||
236 | 198 | ||
237 | fixed->regs_num = MII_REGS_NUM; | 199 | err_regs: |
238 | fixed->phy_status.speed = speed; | 200 | kfree(fp); |
239 | fixed->phy_status.duplex = duplex; | 201 | return ret; |
240 | fixed->phy_status.link = 1; | 202 | } |
203 | EXPORT_SYMBOL_GPL(fixed_phy_add); | ||
241 | 204 | ||
242 | new_bus->name = "Fixed MII Bus"; | 205 | static int __init fixed_mdio_bus_init(void) |
243 | new_bus->read = &fixed_mii_read; | 206 | { |
244 | new_bus->write = &fixed_mii_write; | 207 | struct fixed_mdio_bus *fmb = &platform_fmb; |
245 | new_bus->reset = &fixed_mii_reset; | 208 | int ret; |
246 | /*set up workspace */ | ||
247 | fixed_mdio_update_regs(fixed); | ||
248 | new_bus->priv = fixed; | ||
249 | 209 | ||
250 | new_bus->dev = dev; | 210 | pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0); |
251 | dev_set_drvdata(dev, new_bus); | 211 | if (!pdev) { |
212 | ret = -ENOMEM; | ||
213 | goto err_pdev; | ||
214 | } | ||
252 | 215 | ||
253 | /* create phy_device and register it on the mdio bus */ | 216 | fmb->mii_bus.id = 0; |
254 | phydev = phy_device_create(new_bus, 0, 0); | 217 | fmb->mii_bus.name = "Fixed MDIO Bus"; |
255 | if (phydev == NULL) | 218 | fmb->mii_bus.dev = &pdev->dev; |
256 | goto err_phy_dev_create; | 219 | fmb->mii_bus.read = &fixed_mdio_read; |
220 | fmb->mii_bus.write = &fixed_mdio_write; | ||
221 | fmb->mii_bus.irq = fmb->irqs; | ||
257 | 222 | ||
258 | /* | 223 | ret = mdiobus_register(&fmb->mii_bus); |
259 | * Put the phydev pointer into the fixed pack so that bus read/write | 224 | if (ret) |
260 | * code could be able to access for instance attached netdev. Well it | 225 | goto err_mdiobus_reg; |
261 | * doesn't have to do so, only in case of utilizing user-specified | ||
262 | * link-update... | ||
263 | */ | ||
264 | 226 | ||
265 | fixed->phydev = phydev; | 227 | return 0; |
266 | phydev->speed = speed; | ||
267 | phydev->duplex = duplex; | ||
268 | 228 | ||
269 | phydev->irq = PHY_IGNORE_INTERRUPT; | 229 | err_mdiobus_reg: |
270 | phydev->dev.bus = &mdio_bus_type; | 230 | platform_device_unregister(pdev); |
231 | err_pdev: | ||
232 | return ret; | ||
233 | } | ||
234 | module_init(fixed_mdio_bus_init); | ||
271 | 235 | ||
272 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, | 236 | static void __exit fixed_mdio_bus_exit(void) |
273 | PHY_ID_FMT, bus_id, phy_id); | 237 | { |
238 | struct fixed_mdio_bus *fmb = &platform_fmb; | ||
239 | struct fixed_phy *fp; | ||
274 | 240 | ||
275 | phydev->bus = new_bus; | 241 | mdiobus_unregister(&fmb->mii_bus); |
242 | platform_device_unregister(pdev); | ||
276 | 243 | ||
277 | phydev->dev.driver = &fixed_mdio_driver.driver; | 244 | list_for_each_entry(fp, &fmb->phys, node) { |
278 | phydev->dev.release = fixed_mdio_release; | 245 | list_del(&fp->node); |
279 | err = phydev->dev.driver->probe(&phydev->dev); | 246 | kfree(fp); |
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 | } | 247 | } |
291 | //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX | ||
292 | return fixed; | ||
293 | |||
294 | err_out: | ||
295 | kfree(phydev); | ||
296 | err_phy_dev_create: | ||
297 | kfree(fixed->regs); | ||
298 | err_fixed_regs_alloc: | ||
299 | kfree(fixed); | ||
300 | err_fixed_alloc: | ||
301 | kfree(new_bus); | ||
302 | err_bus_alloc: | ||
303 | kfree(dev); | ||
304 | err_dev_alloc: | ||
305 | |||
306 | return NULL; | ||
307 | |||
308 | } | 248 | } |
309 | #endif | 249 | module_exit(fixed_mdio_bus_exit); |
310 | 250 | ||
311 | MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); | 251 | MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)"); |
312 | MODULE_AUTHOR("Vitaly Bordug"); | 252 | MODULE_AUTHOR("Vitaly Bordug"); |
313 | MODULE_LICENSE("GPL"); | 253 | MODULE_LICENSE("GPL"); |
314 | |||
315 | static 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 | |||
351 | static 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 | |||
361 | module_init(fixed_init); | ||
362 | module_exit(fixed_exit); | ||
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h index 04ba70d49fb8..509d8f5f984e 100644 --- a/include/linux/phy_fixed.h +++ b/include/linux/phy_fixed.h | |||
@@ -1,38 +1,31 @@ | |||
1 | #ifndef __PHY_FIXED_H | 1 | #ifndef __PHY_FIXED_H |
2 | #define __PHY_FIXED_H | 2 | #define __PHY_FIXED_H |
3 | 3 | ||
4 | #define MII_REGS_NUM 29 | ||
5 | |||
6 | /* max number of virtual phy stuff */ | ||
7 | #define MAX_PHY_AMNT 10 | ||
8 | /* | ||
9 | The idea is to emulate normal phy behavior by responding with | ||
10 | pre-defined values to mii BMCR read, so that read_status hook could | ||
11 | take all the needed info. | ||
12 | */ | ||
13 | |||
14 | struct fixed_phy_status { | 4 | struct fixed_phy_status { |
15 | u8 link; | 5 | int link; |
16 | u16 speed; | 6 | int speed; |
17 | u8 duplex; | 7 | int duplex; |
8 | int pause; | ||
9 | int asym_pause; | ||
18 | }; | 10 | }; |
19 | 11 | ||
20 | /*----------------------------------------------------------------------------- | 12 | #ifdef CONFIG_FIXED_PHY |
21 | * Private information hoder for mii_bus | 13 | extern int fixed_phy_add(unsigned int irq, int phy_id, |
22 | *-----------------------------------------------------------------------------*/ | 14 | struct fixed_phy_status *status); |
23 | struct fixed_info { | 15 | #else |
24 | u16 *regs; | 16 | static inline int fixed_phy_add(unsigned int irq, int phy_id, |
25 | u8 regs_num; | 17 | struct fixed_phy_status *status) |
26 | struct fixed_phy_status phy_status; | 18 | { |
27 | struct phy_device *phydev; /* pointer to the container */ | 19 | return -ENODEV; |
28 | /* link & speed cb */ | 20 | } |
29 | int (*link_update) (struct net_device *, struct fixed_phy_status *); | 21 | #endif /* CONFIG_FIXED_PHY */ |
30 | 22 | ||
31 | }; | 23 | /* |
32 | 24 | * This function issued only by fixed_phy-aware drivers, no need | |
33 | 25 | * protect it with #ifdef | |
34 | int fixed_mdio_set_link_update(struct phy_device *, | 26 | */ |
35 | int (*link_update) (struct net_device *, struct fixed_phy_status *)); | 27 | extern int fixed_phy_set_link_update(struct phy_device *phydev, |
36 | struct fixed_info *fixed_mdio_get_phydev (int phydev_ind); | 28 | int (*link_update)(struct net_device *, |
29 | struct fixed_phy_status *)); | ||
37 | 30 | ||
38 | #endif /* __PHY_FIXED_H */ | 31 | #endif /* __PHY_FIXED_H */ |