diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/fixed.c | 33 | ||||
-rw-r--r-- | drivers/net/phy/mdio-bitbang.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/mdio-ofgpio.c | 11 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 232 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 60 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 50 |
6 files changed, 258 insertions, 132 deletions
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 4e07956a483b..cf24cc34debe 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | struct fixed_mdio_bus { | 25 | struct fixed_mdio_bus { |
26 | int irqs[PHY_MAX_ADDR]; | 26 | int irqs[PHY_MAX_ADDR]; |
27 | struct mii_bus mii_bus; | 27 | struct mii_bus *mii_bus; |
28 | struct list_head phys; | 28 | struct list_head phys; |
29 | }; | 29 | }; |
30 | 30 | ||
@@ -115,8 +115,7 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) | |||
115 | 115 | ||
116 | static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num) | 116 | static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num) |
117 | { | 117 | { |
118 | struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus, | 118 | struct fixed_mdio_bus *fmb = bus->priv; |
119 | mii_bus); | ||
120 | struct fixed_phy *fp; | 119 | struct fixed_phy *fp; |
121 | 120 | ||
122 | if (reg_num >= MII_REGS_NUM) | 121 | if (reg_num >= MII_REGS_NUM) |
@@ -213,19 +212,28 @@ static int __init fixed_mdio_bus_init(void) | |||
213 | goto err_pdev; | 212 | goto err_pdev; |
214 | } | 213 | } |
215 | 214 | ||
216 | snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0"); | 215 | fmb->mii_bus = mdiobus_alloc(); |
217 | fmb->mii_bus.name = "Fixed MDIO Bus"; | 216 | if (fmb->mii_bus == NULL) { |
218 | fmb->mii_bus.dev = &pdev->dev; | 217 | ret = -ENOMEM; |
219 | fmb->mii_bus.read = &fixed_mdio_read; | 218 | goto err_mdiobus_reg; |
220 | fmb->mii_bus.write = &fixed_mdio_write; | 219 | } |
221 | fmb->mii_bus.irq = fmb->irqs; | ||
222 | 220 | ||
223 | ret = mdiobus_register(&fmb->mii_bus); | 221 | snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0"); |
222 | fmb->mii_bus->name = "Fixed MDIO Bus"; | ||
223 | fmb->mii_bus->priv = fmb; | ||
224 | fmb->mii_bus->parent = &pdev->dev; | ||
225 | fmb->mii_bus->read = &fixed_mdio_read; | ||
226 | fmb->mii_bus->write = &fixed_mdio_write; | ||
227 | fmb->mii_bus->irq = fmb->irqs; | ||
228 | |||
229 | ret = mdiobus_register(fmb->mii_bus); | ||
224 | if (ret) | 230 | if (ret) |
225 | goto err_mdiobus_reg; | 231 | goto err_mdiobus_alloc; |
226 | 232 | ||
227 | return 0; | 233 | return 0; |
228 | 234 | ||
235 | err_mdiobus_alloc: | ||
236 | mdiobus_free(fmb->mii_bus); | ||
229 | err_mdiobus_reg: | 237 | err_mdiobus_reg: |
230 | platform_device_unregister(pdev); | 238 | platform_device_unregister(pdev); |
231 | err_pdev: | 239 | err_pdev: |
@@ -238,7 +246,8 @@ static void __exit fixed_mdio_bus_exit(void) | |||
238 | struct fixed_mdio_bus *fmb = &platform_fmb; | 246 | struct fixed_mdio_bus *fmb = &platform_fmb; |
239 | struct fixed_phy *fp, *tmp; | 247 | struct fixed_phy *fp, *tmp; |
240 | 248 | ||
241 | mdiobus_unregister(&fmb->mii_bus); | 249 | mdiobus_unregister(fmb->mii_bus); |
250 | mdiobus_free(fmb->mii_bus); | ||
242 | platform_device_unregister(pdev); | 251 | platform_device_unregister(pdev); |
243 | 252 | ||
244 | list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { | 253 | list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { |
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index c01b78013ddc..2576055b350b 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c | |||
@@ -165,7 +165,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) | |||
165 | { | 165 | { |
166 | struct mii_bus *bus; | 166 | struct mii_bus *bus; |
167 | 167 | ||
168 | bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | 168 | bus = mdiobus_alloc(); |
169 | if (!bus) | 169 | if (!bus) |
170 | return NULL; | 170 | return NULL; |
171 | 171 | ||
@@ -184,7 +184,7 @@ void free_mdio_bitbang(struct mii_bus *bus) | |||
184 | struct mdiobb_ctrl *ctrl = bus->priv; | 184 | struct mdiobb_ctrl *ctrl = bus->priv; |
185 | 185 | ||
186 | module_put(ctrl->ops->owner); | 186 | module_put(ctrl->ops->owner); |
187 | kfree(bus); | 187 | mdiobus_free(bus); |
188 | } | 188 | } |
189 | EXPORT_SYMBOL(free_mdio_bitbang); | 189 | EXPORT_SYMBOL(free_mdio_bitbang); |
190 | 190 | ||
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c index 7edfc0c34835..2ff97754e574 100644 --- a/drivers/net/phy/mdio-ofgpio.c +++ b/drivers/net/phy/mdio-ofgpio.c | |||
@@ -122,7 +122,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, | |||
122 | 122 | ||
123 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); | 123 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); |
124 | if (!new_bus) | 124 | if (!new_bus) |
125 | goto out_free_priv; | 125 | goto out_free_bitbang; |
126 | 126 | ||
127 | new_bus->name = "GPIO Bitbanged MII", | 127 | new_bus->name = "GPIO Bitbanged MII", |
128 | 128 | ||
@@ -142,7 +142,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, | |||
142 | if (!strcmp(np->type, "ethernet-phy")) | 142 | if (!strcmp(np->type, "ethernet-phy")) |
143 | add_phy(new_bus, np); | 143 | add_phy(new_bus, np); |
144 | 144 | ||
145 | new_bus->dev = &ofdev->dev; | 145 | new_bus->parent = &ofdev->dev; |
146 | dev_set_drvdata(&ofdev->dev, new_bus); | 146 | dev_set_drvdata(&ofdev->dev, new_bus); |
147 | 147 | ||
148 | ret = mdiobus_register(new_bus); | 148 | ret = mdiobus_register(new_bus); |
@@ -155,9 +155,9 @@ out_free_irqs: | |||
155 | dev_set_drvdata(&ofdev->dev, NULL); | 155 | dev_set_drvdata(&ofdev->dev, NULL); |
156 | kfree(new_bus->irq); | 156 | kfree(new_bus->irq); |
157 | out_free_bus: | 157 | out_free_bus: |
158 | kfree(new_bus); | ||
159 | out_free_priv: | ||
160 | free_mdio_bitbang(new_bus); | 158 | free_mdio_bitbang(new_bus); |
159 | out_free_bitbang: | ||
160 | kfree(bitbang); | ||
161 | out: | 161 | out: |
162 | return ret; | 162 | return ret; |
163 | } | 163 | } |
@@ -168,11 +168,10 @@ static int mdio_ofgpio_remove(struct of_device *ofdev) | |||
168 | struct mdio_gpio_info *bitbang = bus->priv; | 168 | struct mdio_gpio_info *bitbang = bus->priv; |
169 | 169 | ||
170 | mdiobus_unregister(bus); | 170 | mdiobus_unregister(bus); |
171 | kfree(bus->irq); | ||
171 | free_mdio_bitbang(bus); | 172 | free_mdio_bitbang(bus); |
172 | dev_set_drvdata(&ofdev->dev, NULL); | 173 | dev_set_drvdata(&ofdev->dev, NULL); |
173 | kfree(bus->irq); | ||
174 | kfree(bitbang); | 174 | kfree(bitbang); |
175 | kfree(bus); | ||
176 | 175 | ||
177 | return 0; | 176 | return 0; |
178 | } | 177 | } |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 94e0b7ed76f1..d0ed1ef284a8 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -36,6 +36,43 @@ | |||
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * mdiobus_alloc - allocate a mii_bus structure | ||
40 | * | ||
41 | * Description: called by a bus driver to allocate an mii_bus | ||
42 | * structure to fill in. | ||
43 | */ | ||
44 | struct mii_bus *mdiobus_alloc(void) | ||
45 | { | ||
46 | struct mii_bus *bus; | ||
47 | |||
48 | bus = kzalloc(sizeof(*bus), GFP_KERNEL); | ||
49 | if (bus != NULL) | ||
50 | bus->state = MDIOBUS_ALLOCATED; | ||
51 | |||
52 | return bus; | ||
53 | } | ||
54 | EXPORT_SYMBOL(mdiobus_alloc); | ||
55 | |||
56 | /** | ||
57 | * mdiobus_release - mii_bus device release callback | ||
58 | * @d: the target struct device that contains the mii_bus | ||
59 | * | ||
60 | * Description: called when the last reference to an mii_bus is | ||
61 | * dropped, to free the underlying memory. | ||
62 | */ | ||
63 | static void mdiobus_release(struct device *d) | ||
64 | { | ||
65 | struct mii_bus *bus = to_mii_bus(d); | ||
66 | BUG_ON(bus->state != MDIOBUS_RELEASED); | ||
67 | kfree(bus); | ||
68 | } | ||
69 | |||
70 | static struct class mdio_bus_class = { | ||
71 | .name = "mdio_bus", | ||
72 | .dev_release = mdiobus_release, | ||
73 | }; | ||
74 | |||
75 | /** | ||
39 | * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus | 76 | * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus |
40 | * @bus: target mii_bus | 77 | * @bus: target mii_bus |
41 | * | 78 | * |
@@ -54,55 +91,36 @@ int mdiobus_register(struct mii_bus *bus) | |||
54 | NULL == bus->write) | 91 | NULL == bus->write) |
55 | return -EINVAL; | 92 | return -EINVAL; |
56 | 93 | ||
57 | mutex_init(&bus->mdio_lock); | 94 | BUG_ON(bus->state != MDIOBUS_ALLOCATED && |
58 | 95 | bus->state != MDIOBUS_UNREGISTERED); | |
59 | if (bus->reset) | ||
60 | bus->reset(bus); | ||
61 | |||
62 | for (i = 0; i < PHY_MAX_ADDR; i++) { | ||
63 | struct phy_device *phydev; | ||
64 | |||
65 | if (bus->phy_mask & (1 << i)) { | ||
66 | bus->phy_map[i] = NULL; | ||
67 | continue; | ||
68 | } | ||
69 | |||
70 | phydev = get_phy_device(bus, i); | ||
71 | 96 | ||
72 | if (IS_ERR(phydev)) | 97 | bus->dev.parent = bus->parent; |
73 | return PTR_ERR(phydev); | 98 | bus->dev.class = &mdio_bus_class; |
99 | bus->dev.groups = NULL; | ||
100 | memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); | ||
74 | 101 | ||
75 | /* There's a PHY at this address | 102 | err = device_register(&bus->dev); |
76 | * We need to set: | 103 | if (err) { |
77 | * 1) IRQ | 104 | printk(KERN_ERR "mii_bus %s failed to register\n", bus->id); |
78 | * 2) bus_id | 105 | return -EINVAL; |
79 | * 3) parent | 106 | } |
80 | * 4) bus | ||
81 | * 5) mii_bus | ||
82 | * And, we need to register it */ | ||
83 | if (phydev) { | ||
84 | phydev->irq = bus->irq[i]; | ||
85 | 107 | ||
86 | phydev->dev.parent = bus->dev; | 108 | bus->state = MDIOBUS_REGISTERED; |
87 | phydev->dev.bus = &mdio_bus_type; | ||
88 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i); | ||
89 | 109 | ||
90 | phydev->bus = bus; | 110 | mutex_init(&bus->mdio_lock); |
91 | 111 | ||
92 | /* Run all of the fixups for this PHY */ | 112 | if (bus->reset) |
93 | phy_scan_fixups(phydev); | 113 | bus->reset(bus); |
94 | 114 | ||
95 | err = device_register(&phydev->dev); | 115 | for (i = 0; i < PHY_MAX_ADDR; i++) { |
116 | bus->phy_map[i] = NULL; | ||
117 | if ((bus->phy_mask & (1 << i)) == 0) { | ||
118 | struct phy_device *phydev; | ||
96 | 119 | ||
97 | if (err) { | 120 | phydev = mdiobus_scan(bus, i); |
98 | printk(KERN_ERR "phy %d failed to register\n", | 121 | if (IS_ERR(phydev)) |
99 | i); | 122 | err = PTR_ERR(phydev); |
100 | phy_device_free(phydev); | ||
101 | phydev = NULL; | ||
102 | } | ||
103 | } | 123 | } |
104 | |||
105 | bus->phy_map[i] = phydev; | ||
106 | } | 124 | } |
107 | 125 | ||
108 | pr_info("%s: probed\n", bus->name); | 126 | pr_info("%s: probed\n", bus->name); |
@@ -115,6 +133,10 @@ void mdiobus_unregister(struct mii_bus *bus) | |||
115 | { | 133 | { |
116 | int i; | 134 | int i; |
117 | 135 | ||
136 | BUG_ON(bus->state != MDIOBUS_REGISTERED); | ||
137 | bus->state = MDIOBUS_UNREGISTERED; | ||
138 | |||
139 | device_unregister(&bus->dev); | ||
118 | for (i = 0; i < PHY_MAX_ADDR; i++) { | 140 | for (i = 0; i < PHY_MAX_ADDR; i++) { |
119 | if (bus->phy_map[i]) | 141 | if (bus->phy_map[i]) |
120 | device_unregister(&bus->phy_map[i]->dev); | 142 | device_unregister(&bus->phy_map[i]->dev); |
@@ -123,6 +145,122 @@ void mdiobus_unregister(struct mii_bus *bus) | |||
123 | EXPORT_SYMBOL(mdiobus_unregister); | 145 | EXPORT_SYMBOL(mdiobus_unregister); |
124 | 146 | ||
125 | /** | 147 | /** |
148 | * mdiobus_free - free a struct mii_bus | ||
149 | * @bus: mii_bus to free | ||
150 | * | ||
151 | * This function releases the reference to the underlying device | ||
152 | * object in the mii_bus. If this is the last reference, the mii_bus | ||
153 | * will be freed. | ||
154 | */ | ||
155 | void mdiobus_free(struct mii_bus *bus) | ||
156 | { | ||
157 | /* | ||
158 | * For compatibility with error handling in drivers. | ||
159 | */ | ||
160 | if (bus->state == MDIOBUS_ALLOCATED) { | ||
161 | kfree(bus); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | BUG_ON(bus->state != MDIOBUS_UNREGISTERED); | ||
166 | bus->state = MDIOBUS_RELEASED; | ||
167 | |||
168 | put_device(&bus->dev); | ||
169 | } | ||
170 | EXPORT_SYMBOL(mdiobus_free); | ||
171 | |||
172 | struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) | ||
173 | { | ||
174 | struct phy_device *phydev; | ||
175 | int err; | ||
176 | |||
177 | phydev = get_phy_device(bus, addr); | ||
178 | if (IS_ERR(phydev) || phydev == NULL) | ||
179 | return phydev; | ||
180 | |||
181 | /* There's a PHY at this address | ||
182 | * We need to set: | ||
183 | * 1) IRQ | ||
184 | * 2) bus_id | ||
185 | * 3) parent | ||
186 | * 4) bus | ||
187 | * 5) mii_bus | ||
188 | * And, we need to register it */ | ||
189 | |||
190 | phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; | ||
191 | |||
192 | phydev->dev.parent = bus->parent; | ||
193 | phydev->dev.bus = &mdio_bus_type; | ||
194 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); | ||
195 | |||
196 | phydev->bus = bus; | ||
197 | |||
198 | /* Run all of the fixups for this PHY */ | ||
199 | phy_scan_fixups(phydev); | ||
200 | |||
201 | err = device_register(&phydev->dev); | ||
202 | if (err) { | ||
203 | printk(KERN_ERR "phy %d failed to register\n", addr); | ||
204 | phy_device_free(phydev); | ||
205 | phydev = NULL; | ||
206 | } | ||
207 | |||
208 | bus->phy_map[addr] = phydev; | ||
209 | |||
210 | return phydev; | ||
211 | } | ||
212 | EXPORT_SYMBOL(mdiobus_scan); | ||
213 | |||
214 | /** | ||
215 | * mdiobus_read - Convenience function for reading a given MII mgmt register | ||
216 | * @bus: the mii_bus struct | ||
217 | * @addr: the phy address | ||
218 | * @regnum: register number to read | ||
219 | * | ||
220 | * NOTE: MUST NOT be called from interrupt context, | ||
221 | * because the bus read/write functions may wait for an interrupt | ||
222 | * to conclude the operation. | ||
223 | */ | ||
224 | int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum) | ||
225 | { | ||
226 | int retval; | ||
227 | |||
228 | BUG_ON(in_interrupt()); | ||
229 | |||
230 | mutex_lock(&bus->mdio_lock); | ||
231 | retval = bus->read(bus, addr, regnum); | ||
232 | mutex_unlock(&bus->mdio_lock); | ||
233 | |||
234 | return retval; | ||
235 | } | ||
236 | EXPORT_SYMBOL(mdiobus_read); | ||
237 | |||
238 | /** | ||
239 | * mdiobus_write - Convenience function for writing a given MII mgmt register | ||
240 | * @bus: the mii_bus struct | ||
241 | * @addr: the phy address | ||
242 | * @regnum: register number to write | ||
243 | * @val: value to write to @regnum | ||
244 | * | ||
245 | * NOTE: MUST NOT be called from interrupt context, | ||
246 | * because the bus read/write functions may wait for an interrupt | ||
247 | * to conclude the operation. | ||
248 | */ | ||
249 | int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val) | ||
250 | { | ||
251 | int err; | ||
252 | |||
253 | BUG_ON(in_interrupt()); | ||
254 | |||
255 | mutex_lock(&bus->mdio_lock); | ||
256 | err = bus->write(bus, addr, regnum, val); | ||
257 | mutex_unlock(&bus->mdio_lock); | ||
258 | |||
259 | return err; | ||
260 | } | ||
261 | EXPORT_SYMBOL(mdiobus_write); | ||
262 | |||
263 | /** | ||
126 | * mdio_bus_match - determine if given PHY driver supports the given PHY device | 264 | * mdio_bus_match - determine if given PHY driver supports the given PHY device |
127 | * @dev: target PHY device | 265 | * @dev: target PHY device |
128 | * @drv: given PHY driver | 266 | * @drv: given PHY driver |
@@ -174,10 +312,20 @@ EXPORT_SYMBOL(mdio_bus_type); | |||
174 | 312 | ||
175 | int __init mdio_bus_init(void) | 313 | int __init mdio_bus_init(void) |
176 | { | 314 | { |
177 | return bus_register(&mdio_bus_type); | 315 | int ret; |
316 | |||
317 | ret = class_register(&mdio_bus_class); | ||
318 | if (!ret) { | ||
319 | ret = bus_register(&mdio_bus_type); | ||
320 | if (ret) | ||
321 | class_unregister(&mdio_bus_class); | ||
322 | } | ||
323 | |||
324 | return ret; | ||
178 | } | 325 | } |
179 | 326 | ||
180 | void mdio_bus_exit(void) | 327 | void mdio_bus_exit(void) |
181 | { | 328 | { |
329 | class_unregister(&mdio_bus_class); | ||
182 | bus_unregister(&mdio_bus_type); | 330 | bus_unregister(&mdio_bus_type); |
183 | } | 331 | } |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 45cc2914d347..df4e6257d4a7 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -58,55 +58,6 @@ EXPORT_SYMBOL(phy_print_status); | |||
58 | 58 | ||
59 | 59 | ||
60 | /** | 60 | /** |
61 | * phy_read - Convenience function for reading a given PHY register | ||
62 | * @phydev: the phy_device struct | ||
63 | * @regnum: register number to read | ||
64 | * | ||
65 | * NOTE: MUST NOT be called from interrupt context, | ||
66 | * because the bus read/write functions may wait for an interrupt | ||
67 | * to conclude the operation. | ||
68 | */ | ||
69 | int phy_read(struct phy_device *phydev, u16 regnum) | ||
70 | { | ||
71 | int retval; | ||
72 | struct mii_bus *bus = phydev->bus; | ||
73 | |||
74 | BUG_ON(in_interrupt()); | ||
75 | |||
76 | mutex_lock(&bus->mdio_lock); | ||
77 | retval = bus->read(bus, phydev->addr, regnum); | ||
78 | mutex_unlock(&bus->mdio_lock); | ||
79 | |||
80 | return retval; | ||
81 | } | ||
82 | EXPORT_SYMBOL(phy_read); | ||
83 | |||
84 | /** | ||
85 | * phy_write - Convenience function for writing a given PHY register | ||
86 | * @phydev: the phy_device struct | ||
87 | * @regnum: register number to write | ||
88 | * @val: value to write to @regnum | ||
89 | * | ||
90 | * NOTE: MUST NOT be called from interrupt context, | ||
91 | * because the bus read/write functions may wait for an interrupt | ||
92 | * to conclude the operation. | ||
93 | */ | ||
94 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | ||
95 | { | ||
96 | int err; | ||
97 | struct mii_bus *bus = phydev->bus; | ||
98 | |||
99 | BUG_ON(in_interrupt()); | ||
100 | |||
101 | mutex_lock(&bus->mdio_lock); | ||
102 | err = bus->write(bus, phydev->addr, regnum, val); | ||
103 | mutex_unlock(&bus->mdio_lock); | ||
104 | |||
105 | return err; | ||
106 | } | ||
107 | EXPORT_SYMBOL(phy_write); | ||
108 | |||
109 | /** | ||
110 | * phy_clear_interrupt - Ack the phy device's interrupt | 61 | * phy_clear_interrupt - Ack the phy device's interrupt |
111 | * @phydev: the phy_device struct | 62 | * @phydev: the phy_device struct |
112 | * | 63 | * |
@@ -366,7 +317,8 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
366 | switch (cmd) { | 317 | switch (cmd) { |
367 | case SIOCGMIIPHY: | 318 | case SIOCGMIIPHY: |
368 | mii_data->phy_id = phydev->addr; | 319 | mii_data->phy_id = phydev->addr; |
369 | break; | 320 | /* fall through */ |
321 | |||
370 | case SIOCGMIIREG: | 322 | case SIOCGMIIREG: |
371 | mii_data->val_out = phy_read(phydev, mii_data->reg_num); | 323 | mii_data->val_out = phy_read(phydev, mii_data->reg_num); |
372 | break; | 324 | break; |
@@ -413,7 +365,7 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
413 | break; | 365 | break; |
414 | 366 | ||
415 | default: | 367 | default: |
416 | return -ENOTTY; | 368 | return -EOPNOTSUPP; |
417 | } | 369 | } |
418 | 370 | ||
419 | return 0; | 371 | return 0; |
@@ -728,6 +680,12 @@ static void phy_change(struct work_struct *work) | |||
728 | if (err) | 680 | if (err) |
729 | goto irq_enable_err; | 681 | goto irq_enable_err; |
730 | 682 | ||
683 | /* Stop timer and run the state queue now. The work function for | ||
684 | * state_queue will start the timer up again. | ||
685 | */ | ||
686 | del_timer(&phydev->phy_timer); | ||
687 | schedule_work(&phydev->state_queue); | ||
688 | |||
731 | return; | 689 | return; |
732 | 690 | ||
733 | irq_enable_err: | 691 | irq_enable_err: |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 16a0e7de5888..f11e900b437b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -419,13 +419,14 @@ EXPORT_SYMBOL(phy_detach); | |||
419 | * | 419 | * |
420 | * Description: Writes MII_ADVERTISE with the appropriate values, | 420 | * Description: Writes MII_ADVERTISE with the appropriate values, |
421 | * after sanitizing the values to make sure we only advertise | 421 | * after sanitizing the values to make sure we only advertise |
422 | * what is supported. | 422 | * what is supported. Returns < 0 on error, 0 if the PHY's advertisement |
423 | * hasn't changed, and > 0 if it has changed. | ||
423 | */ | 424 | */ |
424 | int genphy_config_advert(struct phy_device *phydev) | 425 | int genphy_config_advert(struct phy_device *phydev) |
425 | { | 426 | { |
426 | u32 advertise; | 427 | u32 advertise; |
427 | int adv; | 428 | int oldadv, adv; |
428 | int err; | 429 | int err, changed = 0; |
429 | 430 | ||
430 | /* Only allow advertising what | 431 | /* Only allow advertising what |
431 | * this PHY supports */ | 432 | * this PHY supports */ |
@@ -433,7 +434,7 @@ int genphy_config_advert(struct phy_device *phydev) | |||
433 | advertise = phydev->advertising; | 434 | advertise = phydev->advertising; |
434 | 435 | ||
435 | /* Setup standard advertisement */ | 436 | /* Setup standard advertisement */ |
436 | adv = phy_read(phydev, MII_ADVERTISE); | 437 | oldadv = adv = phy_read(phydev, MII_ADVERTISE); |
437 | 438 | ||
438 | if (adv < 0) | 439 | if (adv < 0) |
439 | return adv; | 440 | return adv; |
@@ -453,15 +454,18 @@ int genphy_config_advert(struct phy_device *phydev) | |||
453 | if (advertise & ADVERTISED_Asym_Pause) | 454 | if (advertise & ADVERTISED_Asym_Pause) |
454 | adv |= ADVERTISE_PAUSE_ASYM; | 455 | adv |= ADVERTISE_PAUSE_ASYM; |
455 | 456 | ||
456 | err = phy_write(phydev, MII_ADVERTISE, adv); | 457 | if (adv != oldadv) { |
458 | err = phy_write(phydev, MII_ADVERTISE, adv); | ||
457 | 459 | ||
458 | if (err < 0) | 460 | if (err < 0) |
459 | return err; | 461 | return err; |
462 | changed = 1; | ||
463 | } | ||
460 | 464 | ||
461 | /* Configure gigabit if it's supported */ | 465 | /* Configure gigabit if it's supported */ |
462 | if (phydev->supported & (SUPPORTED_1000baseT_Half | | 466 | if (phydev->supported & (SUPPORTED_1000baseT_Half | |
463 | SUPPORTED_1000baseT_Full)) { | 467 | SUPPORTED_1000baseT_Full)) { |
464 | adv = phy_read(phydev, MII_CTRL1000); | 468 | oldadv = adv = phy_read(phydev, MII_CTRL1000); |
465 | 469 | ||
466 | if (adv < 0) | 470 | if (adv < 0) |
467 | return adv; | 471 | return adv; |
@@ -471,13 +475,17 @@ int genphy_config_advert(struct phy_device *phydev) | |||
471 | adv |= ADVERTISE_1000HALF; | 475 | adv |= ADVERTISE_1000HALF; |
472 | if (advertise & SUPPORTED_1000baseT_Full) | 476 | if (advertise & SUPPORTED_1000baseT_Full) |
473 | adv |= ADVERTISE_1000FULL; | 477 | adv |= ADVERTISE_1000FULL; |
474 | err = phy_write(phydev, MII_CTRL1000, adv); | ||
475 | 478 | ||
476 | if (err < 0) | 479 | if (adv != oldadv) { |
477 | return err; | 480 | err = phy_write(phydev, MII_CTRL1000, adv); |
481 | |||
482 | if (err < 0) | ||
483 | return err; | ||
484 | changed = 1; | ||
485 | } | ||
478 | } | 486 | } |
479 | 487 | ||
480 | return adv; | 488 | return changed; |
481 | } | 489 | } |
482 | EXPORT_SYMBOL(genphy_config_advert); | 490 | EXPORT_SYMBOL(genphy_config_advert); |
483 | 491 | ||
@@ -549,6 +557,7 @@ int genphy_restart_aneg(struct phy_device *phydev) | |||
549 | 557 | ||
550 | return ctl; | 558 | return ctl; |
551 | } | 559 | } |
560 | EXPORT_SYMBOL(genphy_restart_aneg); | ||
552 | 561 | ||
553 | 562 | ||
554 | /** | 563 | /** |
@@ -561,19 +570,22 @@ int genphy_restart_aneg(struct phy_device *phydev) | |||
561 | */ | 570 | */ |
562 | int genphy_config_aneg(struct phy_device *phydev) | 571 | int genphy_config_aneg(struct phy_device *phydev) |
563 | { | 572 | { |
564 | int err = 0; | 573 | int result = 0; |
565 | 574 | ||
566 | if (AUTONEG_ENABLE == phydev->autoneg) { | 575 | if (AUTONEG_ENABLE == phydev->autoneg) { |
567 | err = genphy_config_advert(phydev); | 576 | int result = genphy_config_advert(phydev); |
568 | 577 | ||
569 | if (err < 0) | 578 | if (result < 0) /* error */ |
570 | return err; | 579 | return result; |
571 | 580 | ||
572 | err = genphy_restart_aneg(phydev); | 581 | /* Only restart aneg if we are advertising something different |
582 | * than we were before. */ | ||
583 | if (result > 0) | ||
584 | result = genphy_restart_aneg(phydev); | ||
573 | } else | 585 | } else |
574 | err = genphy_setup_forced(phydev); | 586 | result = genphy_setup_forced(phydev); |
575 | 587 | ||
576 | return err; | 588 | return result; |
577 | } | 589 | } |
578 | EXPORT_SYMBOL(genphy_config_aneg); | 590 | EXPORT_SYMBOL(genphy_config_aneg); |
579 | 591 | ||