diff options
author | Andy Fleming <afleming@freescale.com> | 2005-07-30 19:31:23 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-07-30 19:31:23 -0400 |
commit | 00db8189d984d6c51226dafbbe4a667ce9b7d5da (patch) | |
tree | f19468548c938523e3519670f8554e7a1b9c0c31 /drivers/net | |
parent | b0825488a642cadcf39709961dde61440cb0731c (diff) |
This patch adds a PHY Abstraction Layer to the Linux Kernel, enabling
ethernet drivers to remain as ignorant as is reasonable of the connected
PHY's design and operation details.
Signed-off-by: Andy Fleming <afleming@freescale.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/Kconfig | 57 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 9 | ||||
-rw-r--r-- | drivers/net/phy/cicada.c | 134 | ||||
-rw-r--r-- | drivers/net/phy/davicom.c | 195 | ||||
-rw-r--r-- | drivers/net/phy/lxt.c | 179 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 140 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 173 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 862 | ||||
-rw-r--r-- | drivers/net/phy/phy.c.orig | 860 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 682 | ||||
-rw-r--r-- | drivers/net/phy/qsemi.c | 143 |
13 files changed, 3437 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8a835eb58808..1e50b8e32add 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -131,6 +131,8 @@ config NET_SB1000 | |||
131 | 131 | ||
132 | source "drivers/net/arcnet/Kconfig" | 132 | source "drivers/net/arcnet/Kconfig" |
133 | 133 | ||
134 | source "drivers/net/phy/Kconfig" | ||
135 | |||
134 | # | 136 | # |
135 | # Ethernet | 137 | # Ethernet |
136 | # | 138 | # |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 63c6d1e6d4d9..a369ae284a9a 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -65,6 +65,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o | |||
65 | # | 65 | # |
66 | 66 | ||
67 | obj-$(CONFIG_MII) += mii.o | 67 | obj-$(CONFIG_MII) += mii.o |
68 | obj-$(CONFIG_PHYLIB) += phy/ | ||
68 | 69 | ||
69 | obj-$(CONFIG_SUNDANCE) += sundance.o | 70 | obj-$(CONFIG_SUNDANCE) += sundance.o |
70 | obj-$(CONFIG_HAMACHI) += hamachi.o | 71 | obj-$(CONFIG_HAMACHI) += hamachi.o |
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig new file mode 100644 index 000000000000..8b5db2343cc3 --- /dev/null +++ b/drivers/net/phy/Kconfig | |||
@@ -0,0 +1,57 @@ | |||
1 | # | ||
2 | # PHY Layer Configuration | ||
3 | # | ||
4 | |||
5 | menu "PHY device support" | ||
6 | |||
7 | config PHYLIB | ||
8 | bool "PHY Device support and infrastructure" | ||
9 | depends on NET_ETHERNET | ||
10 | help | ||
11 | Ethernet controllers are usually attached to PHY | ||
12 | devices. This option provides infrastructure for | ||
13 | managing PHY devices. | ||
14 | |||
15 | config PHYCONTROL | ||
16 | bool "Support for automatically handling PHY state changes" | ||
17 | depends on PHYLIB | ||
18 | help | ||
19 | Adds code to perform all the work for keeping PHY link | ||
20 | state (speed/duplex/etc) up-to-date. Also handles | ||
21 | interrupts. | ||
22 | |||
23 | comment "MII PHY device drivers" | ||
24 | depends on PHYLIB | ||
25 | |||
26 | config MARVELL_PHY | ||
27 | bool "Drivers for Marvell PHYs" | ||
28 | depends on PHYLIB | ||
29 | ---help--- | ||
30 | Currently has a driver for the 88E1011S | ||
31 | |||
32 | config DAVICOM_PHY | ||
33 | bool "Drivers for Davicom PHYs" | ||
34 | depends on PHYLIB | ||
35 | ---help--- | ||
36 | Currently supports dm9161e and dm9131 | ||
37 | |||
38 | config QSEMI_PHY | ||
39 | bool "Drivers for Quality Semiconductor PHYs" | ||
40 | depends on PHYLIB | ||
41 | ---help--- | ||
42 | Currently supports the qs6612 | ||
43 | |||
44 | config LXT_PHY | ||
45 | bool "Drivers for the Intel LXT PHYs" | ||
46 | depends on PHYLIB | ||
47 | ---help--- | ||
48 | Currently supports the lxt970, lxt971 | ||
49 | |||
50 | config CICADA_PHY | ||
51 | bool "Drivers for the Cicada PHYs" | ||
52 | depends on PHYLIB | ||
53 | ---help--- | ||
54 | Currently supports the cis8204 | ||
55 | |||
56 | endmenu | ||
57 | |||
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile new file mode 100644 index 000000000000..1af05de6ced0 --- /dev/null +++ b/drivers/net/phy/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for Linux PHY drivers | ||
2 | |||
3 | obj-$(CONFIG_PHYLIB) += phy.o phy_device.o mdio_bus.o | ||
4 | |||
5 | obj-$(CONFIG_MARVELL_PHY) += marvell.o | ||
6 | obj-$(CONFIG_DAVICOM_PHY) += davicom.o | ||
7 | obj-$(CONFIG_CICADA_PHY) += cicada.o | ||
8 | obj-$(CONFIG_LXT_PHY) += lxt.o | ||
9 | obj-$(CONFIG_QSEMI_PHY) += qsemi.o | ||
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c new file mode 100644 index 000000000000..c47fb2ecd147 --- /dev/null +++ b/drivers/net/phy/cicada.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/cicada.c | ||
3 | * | ||
4 | * Driver for Cicada PHYs | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | /* Cicada Extended Control Register 1 */ | ||
42 | #define MII_CIS8201_EXT_CON1 0x17 | ||
43 | #define MII_CIS8201_EXTCON1_INIT 0x0000 | ||
44 | |||
45 | /* Cicada Interrupt Mask Register */ | ||
46 | #define MII_CIS8201_IMASK 0x19 | ||
47 | #define MII_CIS8201_IMASK_IEN 0x8000 | ||
48 | #define MII_CIS8201_IMASK_SPEED 0x4000 | ||
49 | #define MII_CIS8201_IMASK_LINK 0x2000 | ||
50 | #define MII_CIS8201_IMASK_DUPLEX 0x1000 | ||
51 | #define MII_CIS8201_IMASK_MASK 0xf000 | ||
52 | |||
53 | /* Cicada Interrupt Status Register */ | ||
54 | #define MII_CIS8201_ISTAT 0x1a | ||
55 | #define MII_CIS8201_ISTAT_STATUS 0x8000 | ||
56 | #define MII_CIS8201_ISTAT_SPEED 0x4000 | ||
57 | #define MII_CIS8201_ISTAT_LINK 0x2000 | ||
58 | #define MII_CIS8201_ISTAT_DUPLEX 0x1000 | ||
59 | |||
60 | /* Cicada Auxiliary Control/Status Register */ | ||
61 | #define MII_CIS8201_AUX_CONSTAT 0x1c | ||
62 | #define MII_CIS8201_AUXCONSTAT_INIT 0x0004 | ||
63 | #define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 | ||
64 | #define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 | ||
65 | #define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 | ||
66 | #define MII_CIS8201_AUXCONSTAT_100 0x0008 | ||
67 | |||
68 | MODULE_DESCRIPTION("Cicadia PHY driver"); | ||
69 | MODULE_AUTHOR("Andy Fleming"); | ||
70 | MODULE_LICENSE("GPL"); | ||
71 | |||
72 | static int cis820x_config_init(struct phy_device *phydev) | ||
73 | { | ||
74 | int err; | ||
75 | |||
76 | err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT, | ||
77 | MII_CIS8201_AUXCONSTAT_INIT); | ||
78 | |||
79 | if (err < 0) | ||
80 | return err; | ||
81 | |||
82 | err = phy_write(phydev, MII_CIS8201_EXT_CON1, | ||
83 | MII_CIS8201_EXTCON1_INIT); | ||
84 | |||
85 | return err; | ||
86 | } | ||
87 | |||
88 | static int cis820x_ack_interrupt(struct phy_device *phydev) | ||
89 | { | ||
90 | int err = phy_read(phydev, MII_CIS8201_ISTAT); | ||
91 | |||
92 | return (err < 0) ? err : 0; | ||
93 | } | ||
94 | |||
95 | static int cis820x_config_intr(struct phy_device *phydev) | ||
96 | { | ||
97 | int err; | ||
98 | |||
99 | if(phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
100 | err = phy_write(phydev, MII_CIS8201_IMASK, | ||
101 | MII_CIS8201_IMASK_MASK); | ||
102 | else | ||
103 | err = phy_write(phydev, MII_CIS8201_IMASK, 0); | ||
104 | |||
105 | return err; | ||
106 | } | ||
107 | |||
108 | /* Cicada 820x */ | ||
109 | static struct phy_driver cis8204_driver = { | ||
110 | .phy_id = 0x000fc440, | ||
111 | .name = "Cicada Cis8204", | ||
112 | .phy_id_mask = 0x000fffc0, | ||
113 | .features = PHY_GBIT_FEATURES, | ||
114 | .flags = PHY_HAS_INTERRUPT, | ||
115 | .config_init = &cis820x_config_init, | ||
116 | .config_aneg = &genphy_config_aneg, | ||
117 | .read_status = &genphy_read_status, | ||
118 | .ack_interrupt = &cis820x_ack_interrupt, | ||
119 | .config_intr = &cis820x_config_intr, | ||
120 | .driver = { .owner = THIS_MODULE,}, | ||
121 | }; | ||
122 | |||
123 | static int __init cis8204_init(void) | ||
124 | { | ||
125 | return phy_driver_register(&cis8204_driver); | ||
126 | } | ||
127 | |||
128 | static void __exit cis8204_exit(void) | ||
129 | { | ||
130 | phy_driver_unregister(&cis8204_driver); | ||
131 | } | ||
132 | |||
133 | module_init(cis8204_init); | ||
134 | module_exit(cis8204_exit); | ||
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 000000000000..6caf499fae32 --- /dev/null +++ b/drivers/net/phy/davicom.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/davicom.c | ||
3 | * | ||
4 | * Driver for Davicom PHYs | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #define MII_DM9161_SCR 0x10 | ||
42 | #define MII_DM9161_SCR_INIT 0x0610 | ||
43 | |||
44 | /* DM9161 Interrupt Register */ | ||
45 | #define MII_DM9161_INTR 0x15 | ||
46 | #define MII_DM9161_INTR_PEND 0x8000 | ||
47 | #define MII_DM9161_INTR_DPLX_MASK 0x0800 | ||
48 | #define MII_DM9161_INTR_SPD_MASK 0x0400 | ||
49 | #define MII_DM9161_INTR_LINK_MASK 0x0200 | ||
50 | #define MII_DM9161_INTR_MASK 0x0100 | ||
51 | #define MII_DM9161_INTR_DPLX_CHANGE 0x0010 | ||
52 | #define MII_DM9161_INTR_SPD_CHANGE 0x0008 | ||
53 | #define MII_DM9161_INTR_LINK_CHANGE 0x0004 | ||
54 | #define MII_DM9161_INTR_INIT 0x0000 | ||
55 | #define MII_DM9161_INTR_STOP \ | ||
56 | (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ | ||
57 | | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) | ||
58 | |||
59 | /* DM9161 10BT Configuration/Status */ | ||
60 | #define MII_DM9161_10BTCSR 0x12 | ||
61 | #define MII_DM9161_10BTCSR_INIT 0x7800 | ||
62 | |||
63 | MODULE_DESCRIPTION("Davicom PHY driver"); | ||
64 | MODULE_AUTHOR("Andy Fleming"); | ||
65 | MODULE_LICENSE("GPL"); | ||
66 | |||
67 | |||
68 | #define DM9161_DELAY 1 | ||
69 | static int dm9161_config_intr(struct phy_device *phydev) | ||
70 | { | ||
71 | int temp; | ||
72 | |||
73 | temp = phy_read(phydev, MII_DM9161_INTR); | ||
74 | |||
75 | if (temp < 0) | ||
76 | return temp; | ||
77 | |||
78 | if(PHY_INTERRUPT_ENABLED == phydev->interrupts ) | ||
79 | temp &= ~(MII_DM9161_INTR_STOP); | ||
80 | else | ||
81 | temp |= MII_DM9161_INTR_STOP; | ||
82 | |||
83 | temp = phy_write(phydev, MII_DM9161_INTR, temp); | ||
84 | |||
85 | return temp; | ||
86 | } | ||
87 | |||
88 | static int dm9161_config_aneg(struct phy_device *phydev) | ||
89 | { | ||
90 | int err; | ||
91 | |||
92 | /* Isolate the PHY */ | ||
93 | err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); | ||
94 | |||
95 | if (err < 0) | ||
96 | return err; | ||
97 | |||
98 | /* Configure the new settings */ | ||
99 | err = genphy_config_aneg(phydev); | ||
100 | |||
101 | if (err < 0) | ||
102 | return err; | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int dm9161_config_init(struct phy_device *phydev) | ||
108 | { | ||
109 | int err; | ||
110 | |||
111 | /* Isolate the PHY */ | ||
112 | err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); | ||
113 | |||
114 | if (err < 0) | ||
115 | return err; | ||
116 | |||
117 | /* Do not bypass the scrambler/descrambler */ | ||
118 | err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT); | ||
119 | |||
120 | if (err < 0) | ||
121 | return err; | ||
122 | |||
123 | /* Clear 10BTCSR to default */ | ||
124 | err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); | ||
125 | |||
126 | if (err < 0) | ||
127 | return err; | ||
128 | |||
129 | /* Reconnect the PHY, and enable Autonegotiation */ | ||
130 | err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE); | ||
131 | |||
132 | if (err < 0) | ||
133 | return err; | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int dm9161_ack_interrupt(struct phy_device *phydev) | ||
139 | { | ||
140 | int err = phy_read(phydev, MII_DM9161_INTR); | ||
141 | |||
142 | return (err < 0) ? err : 0; | ||
143 | } | ||
144 | |||
145 | static struct phy_driver dm9161_driver = { | ||
146 | .phy_id = 0x0181b880, | ||
147 | .name = "Davicom DM9161E", | ||
148 | .phy_id_mask = 0x0ffffff0, | ||
149 | .features = PHY_BASIC_FEATURES, | ||
150 | .config_init = dm9161_config_init, | ||
151 | .config_aneg = dm9161_config_aneg, | ||
152 | .read_status = genphy_read_status, | ||
153 | .driver = { .owner = THIS_MODULE,}, | ||
154 | }; | ||
155 | |||
156 | static struct phy_driver dm9131_driver = { | ||
157 | .phy_id = 0x00181b80, | ||
158 | .name = "Davicom DM9131", | ||
159 | .phy_id_mask = 0x0ffffff0, | ||
160 | .features = PHY_BASIC_FEATURES, | ||
161 | .flags = PHY_HAS_INTERRUPT, | ||
162 | .config_aneg = genphy_config_aneg, | ||
163 | .read_status = genphy_read_status, | ||
164 | .ack_interrupt = dm9161_ack_interrupt, | ||
165 | .config_intr = dm9161_config_intr, | ||
166 | .driver = { .owner = THIS_MODULE,}, | ||
167 | }; | ||
168 | |||
169 | static int __init davicom_init(void) | ||
170 | { | ||
171 | int ret; | ||
172 | |||
173 | ret = phy_driver_register(&dm9161_driver); | ||
174 | if (ret) | ||
175 | goto err1; | ||
176 | |||
177 | ret = phy_driver_register(&dm9131_driver); | ||
178 | if (ret) | ||
179 | goto err2; | ||
180 | return 0; | ||
181 | |||
182 | err2: | ||
183 | phy_driver_unregister(&dm9161_driver); | ||
184 | err1: | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static void __exit davicom_exit(void) | ||
189 | { | ||
190 | phy_driver_unregister(&dm9161_driver); | ||
191 | phy_driver_unregister(&dm9131_driver); | ||
192 | } | ||
193 | |||
194 | module_init(davicom_init); | ||
195 | module_exit(davicom_exit); | ||
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 000000000000..4c840448ec86 --- /dev/null +++ b/drivers/net/phy/lxt.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/lxt.c | ||
3 | * | ||
4 | * Driver for Intel LXT PHYs | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | /* The Level one LXT970 is used by many boards */ | ||
42 | |||
43 | #define MII_LXT970_IER 17 /* Interrupt Enable Register */ | ||
44 | |||
45 | #define MII_LXT970_IER_IEN 0x0002 | ||
46 | |||
47 | #define MII_LXT970_ISR 18 /* Interrupt Status Register */ | ||
48 | |||
49 | #define MII_LXT970_CONFIG 19 /* Configuration Register */ | ||
50 | |||
51 | /* ------------------------------------------------------------------------- */ | ||
52 | /* The Level one LXT971 is used on some of my custom boards */ | ||
53 | |||
54 | /* register definitions for the 971 */ | ||
55 | #define MII_LXT971_IER 18 /* Interrupt Enable Register */ | ||
56 | #define MII_LXT971_IER_IEN 0x00f2 | ||
57 | |||
58 | #define MII_LXT971_ISR 19 /* Interrupt Status Register */ | ||
59 | |||
60 | |||
61 | MODULE_DESCRIPTION("Intel LXT PHY driver"); | ||
62 | MODULE_AUTHOR("Andy Fleming"); | ||
63 | MODULE_LICENSE("GPL"); | ||
64 | |||
65 | static int lxt970_ack_interrupt(struct phy_device *phydev) | ||
66 | { | ||
67 | int err; | ||
68 | |||
69 | err = phy_read(phydev, MII_BMSR); | ||
70 | |||
71 | if (err < 0) | ||
72 | return err; | ||
73 | |||
74 | err = phy_read(phydev, MII_LXT970_ISR); | ||
75 | |||
76 | if (err < 0) | ||
77 | return err; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int lxt970_config_intr(struct phy_device *phydev) | ||
83 | { | ||
84 | int err; | ||
85 | |||
86 | if(phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
87 | err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); | ||
88 | else | ||
89 | err = phy_write(phydev, MII_LXT970_IER, 0); | ||
90 | |||
91 | return err; | ||
92 | } | ||
93 | |||
94 | static int lxt970_config_init(struct phy_device *phydev) | ||
95 | { | ||
96 | int err; | ||
97 | |||
98 | err = phy_write(phydev, MII_LXT970_CONFIG, 0); | ||
99 | |||
100 | return err; | ||
101 | } | ||
102 | |||
103 | |||
104 | static int lxt971_ack_interrupt(struct phy_device *phydev) | ||
105 | { | ||
106 | int err = phy_read(phydev, MII_LXT971_ISR); | ||
107 | |||
108 | if (err < 0) | ||
109 | return err; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int lxt971_config_intr(struct phy_device *phydev) | ||
115 | { | ||
116 | int err; | ||
117 | |||
118 | if(phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
119 | err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); | ||
120 | else | ||
121 | err = phy_write(phydev, MII_LXT971_IER, 0); | ||
122 | |||
123 | return err; | ||
124 | } | ||
125 | |||
126 | static struct phy_driver lxt970_driver = { | ||
127 | .phy_id = 0x07810000, | ||
128 | .name = "LXT970", | ||
129 | .phy_id_mask = 0x0fffffff, | ||
130 | .features = PHY_BASIC_FEATURES, | ||
131 | .flags = PHY_HAS_INTERRUPT, | ||
132 | .config_init = lxt970_config_init, | ||
133 | .config_aneg = genphy_config_aneg, | ||
134 | .read_status = genphy_read_status, | ||
135 | .ack_interrupt = lxt970_ack_interrupt, | ||
136 | .config_intr = lxt970_config_intr, | ||
137 | .driver = { .owner = THIS_MODULE,}, | ||
138 | }; | ||
139 | |||
140 | static struct phy_driver lxt971_driver = { | ||
141 | .phy_id = 0x0001378e, | ||
142 | .name = "LXT971", | ||
143 | .phy_id_mask = 0x0fffffff, | ||
144 | .features = PHY_BASIC_FEATURES, | ||
145 | .flags = PHY_HAS_INTERRUPT, | ||
146 | .config_aneg = genphy_config_aneg, | ||
147 | .read_status = genphy_read_status, | ||
148 | .ack_interrupt = lxt971_ack_interrupt, | ||
149 | .config_intr = lxt971_config_intr, | ||
150 | .driver = { .owner = THIS_MODULE,}, | ||
151 | }; | ||
152 | |||
153 | static int __init lxt_init(void) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | ret = phy_driver_register(&lxt970_driver); | ||
158 | if (ret) | ||
159 | goto err1; | ||
160 | |||
161 | ret = phy_driver_register(&lxt971_driver); | ||
162 | if (ret) | ||
163 | goto err2; | ||
164 | return 0; | ||
165 | |||
166 | err2: | ||
167 | phy_driver_unregister(&lxt970_driver); | ||
168 | err1: | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static void __exit lxt_exit(void) | ||
173 | { | ||
174 | phy_driver_unregister(&lxt970_driver); | ||
175 | phy_driver_unregister(&lxt971_driver); | ||
176 | } | ||
177 | |||
178 | module_init(lxt_init); | ||
179 | module_exit(lxt_exit); | ||
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 000000000000..4a72b025006b --- /dev/null +++ b/drivers/net/phy/marvell.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/marvell.c | ||
3 | * | ||
4 | * Driver for Marvell PHYs | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #define MII_M1011_IEVENT 0x13 | ||
42 | #define MII_M1011_IEVENT_CLEAR 0x0000 | ||
43 | |||
44 | #define MII_M1011_IMASK 0x12 | ||
45 | #define MII_M1011_IMASK_INIT 0x6400 | ||
46 | #define MII_M1011_IMASK_CLEAR 0x0000 | ||
47 | |||
48 | MODULE_DESCRIPTION("Marvell PHY driver"); | ||
49 | MODULE_AUTHOR("Andy Fleming"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | static int marvell_ack_interrupt(struct phy_device *phydev) | ||
53 | { | ||
54 | int err; | ||
55 | |||
56 | /* Clear the interrupts by reading the reg */ | ||
57 | err = phy_read(phydev, MII_M1011_IEVENT); | ||
58 | |||
59 | if (err < 0) | ||
60 | return err; | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int marvell_config_intr(struct phy_device *phydev) | ||
66 | { | ||
67 | int err; | ||
68 | |||
69 | if(phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
70 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); | ||
71 | else | ||
72 | err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); | ||
73 | |||
74 | return err; | ||
75 | } | ||
76 | |||
77 | static int marvell_config_aneg(struct phy_device *phydev) | ||
78 | { | ||
79 | int err; | ||
80 | |||
81 | /* The Marvell PHY has an errata which requires | ||
82 | * that certain registers get written in order | ||
83 | * to restart autonegotiation */ | ||
84 | err = phy_write(phydev, MII_BMCR, BMCR_RESET); | ||
85 | |||
86 | if (err < 0) | ||
87 | return err; | ||
88 | |||
89 | err = phy_write(phydev, 0x1d, 0x1f); | ||
90 | if (err < 0) | ||
91 | return err; | ||
92 | |||
93 | err = phy_write(phydev, 0x1e, 0x200c); | ||
94 | if (err < 0) | ||
95 | return err; | ||
96 | |||
97 | err = phy_write(phydev, 0x1d, 0x5); | ||
98 | if (err < 0) | ||
99 | return err; | ||
100 | |||
101 | err = phy_write(phydev, 0x1e, 0); | ||
102 | if (err < 0) | ||
103 | return err; | ||
104 | |||
105 | err = phy_write(phydev, 0x1e, 0x100); | ||
106 | if (err < 0) | ||
107 | return err; | ||
108 | |||
109 | |||
110 | err = genphy_config_aneg(phydev); | ||
111 | |||
112 | return err; | ||
113 | } | ||
114 | |||
115 | |||
116 | static struct phy_driver m88e1101_driver = { | ||
117 | .phy_id = 0x01410c00, | ||
118 | .phy_id_mask = 0xffffff00, | ||
119 | .name = "Marvell 88E1101", | ||
120 | .features = PHY_GBIT_FEATURES, | ||
121 | .flags = PHY_HAS_INTERRUPT, | ||
122 | .config_aneg = &marvell_config_aneg, | ||
123 | .read_status = &genphy_read_status, | ||
124 | .ack_interrupt = &marvell_ack_interrupt, | ||
125 | .config_intr = &marvell_config_intr, | ||
126 | .driver = { .owner = THIS_MODULE,}, | ||
127 | }; | ||
128 | |||
129 | static int __init marvell_init(void) | ||
130 | { | ||
131 | return phy_driver_register(&m88e1101_driver); | ||
132 | } | ||
133 | |||
134 | static void __exit marvell_exit(void) | ||
135 | { | ||
136 | phy_driver_unregister(&m88e1101_driver); | ||
137 | } | ||
138 | |||
139 | module_init(marvell_init); | ||
140 | module_exit(marvell_exit); | ||
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c new file mode 100644 index 000000000000..e75103ba6f86 --- /dev/null +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/mdio_bus.c | ||
3 | * | ||
4 | * MDIO Bus interface | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | /* mdiobus_register | ||
42 | * | ||
43 | * description: Called by a bus driver to bring up all the PHYs | ||
44 | * on a given bus, and attach them to the bus | ||
45 | */ | ||
46 | int mdiobus_register(struct mii_bus *bus) | ||
47 | { | ||
48 | int i; | ||
49 | int err = 0; | ||
50 | |||
51 | spin_lock_init(&bus->mdio_lock); | ||
52 | |||
53 | if (NULL == bus || NULL == bus->name || | ||
54 | NULL == bus->read || | ||
55 | NULL == bus->write) | ||
56 | return -EINVAL; | ||
57 | |||
58 | if (bus->reset) | ||
59 | bus->reset(bus); | ||
60 | |||
61 | for (i = 0; i < PHY_MAX_ADDR; i++) { | ||
62 | struct phy_device *phydev; | ||
63 | |||
64 | phydev = get_phy_device(bus, i); | ||
65 | |||
66 | if (IS_ERR(phydev)) | ||
67 | return PTR_ERR(phydev); | ||
68 | |||
69 | /* There's a PHY at this address | ||
70 | * We need to set: | ||
71 | * 1) IRQ | ||
72 | * 2) bus_id | ||
73 | * 3) parent | ||
74 | * 4) bus | ||
75 | * 5) mii_bus | ||
76 | * And, we need to register it */ | ||
77 | if (phydev) { | ||
78 | phydev->irq = bus->irq[i]; | ||
79 | |||
80 | phydev->dev.parent = bus->dev; | ||
81 | phydev->dev.bus = &mdio_bus_type; | ||
82 | sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); | ||
83 | |||
84 | phydev->bus = bus; | ||
85 | |||
86 | err = device_register(&phydev->dev); | ||
87 | |||
88 | if (err) | ||
89 | printk(KERN_ERR "phy %d failed to register\n", | ||
90 | i); | ||
91 | } | ||
92 | |||
93 | bus->phy_map[i] = phydev; | ||
94 | } | ||
95 | |||
96 | pr_info("%s: probed\n", bus->name); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | EXPORT_SYMBOL(mdiobus_register); | ||
101 | |||
102 | void mdiobus_unregister(struct mii_bus *bus) | ||
103 | { | ||
104 | int i; | ||
105 | |||
106 | for (i = 0; i < PHY_MAX_ADDR; i++) { | ||
107 | if (bus->phy_map[i]) { | ||
108 | device_unregister(&bus->phy_map[i]->dev); | ||
109 | kfree(bus->phy_map[i]); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | EXPORT_SYMBOL(mdiobus_unregister); | ||
114 | |||
115 | /* mdio_bus_match | ||
116 | * | ||
117 | * description: Given a PHY device, and a PHY driver, return 1 if | ||
118 | * the driver supports the device. Otherwise, return 0 | ||
119 | */ | ||
120 | static int mdio_bus_match(struct device *dev, struct device_driver *drv) | ||
121 | { | ||
122 | struct phy_device *phydev = to_phy_device(dev); | ||
123 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
124 | |||
125 | return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask)); | ||
126 | } | ||
127 | |||
128 | /* Suspend and resume. Copied from platform_suspend and | ||
129 | * platform_resume | ||
130 | */ | ||
131 | static int mdio_bus_suspend(struct device * dev, u32 state) | ||
132 | { | ||
133 | int ret = 0; | ||
134 | struct device_driver *drv = dev->driver; | ||
135 | |||
136 | if (drv && drv->suspend) { | ||
137 | ret = drv->suspend(dev, state, SUSPEND_DISABLE); | ||
138 | if (ret == 0) | ||
139 | ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); | ||
140 | if (ret == 0) | ||
141 | ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); | ||
142 | } | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | static int mdio_bus_resume(struct device * dev) | ||
147 | { | ||
148 | int ret = 0; | ||
149 | struct device_driver *drv = dev->driver; | ||
150 | |||
151 | if (drv && drv->resume) { | ||
152 | ret = drv->resume(dev, RESUME_POWER_ON); | ||
153 | if (ret == 0) | ||
154 | ret = drv->resume(dev, RESUME_RESTORE_STATE); | ||
155 | if (ret == 0) | ||
156 | ret = drv->resume(dev, RESUME_ENABLE); | ||
157 | } | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | struct bus_type mdio_bus_type = { | ||
162 | .name = "mdio_bus", | ||
163 | .match = mdio_bus_match, | ||
164 | .suspend = mdio_bus_suspend, | ||
165 | .resume = mdio_bus_resume, | ||
166 | }; | ||
167 | |||
168 | static int __init mdio_bus_init(void) | ||
169 | { | ||
170 | return bus_register(&mdio_bus_type); | ||
171 | } | ||
172 | |||
173 | subsys_initcall(mdio_bus_init); | ||
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c new file mode 100644 index 000000000000..e2c6896b92d2 --- /dev/null +++ b/drivers/net/phy/phy.c | |||
@@ -0,0 +1,862 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/phy.c | ||
3 | * | ||
4 | * Framework for configuring and reading PHY devices | ||
5 | * Based on code in sungem_phy.c and gianfar_phy.c | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * | ||
9 | * Copyright (c) 2004 Freescale Semiconductor, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/phy.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | static void phy_change(void *data); | ||
43 | static void phy_timer(unsigned long data); | ||
44 | |||
45 | /* Convenience function to print out the current phy status | ||
46 | */ | ||
47 | void phy_print_status(struct phy_device *phydev) | ||
48 | { | ||
49 | pr_info("%s: Link is %s", phydev->dev.bus_id, | ||
50 | phydev->link ? "Up" : "Down"); | ||
51 | if (phydev->link) | ||
52 | printk(" - %d/%s", phydev->speed, | ||
53 | DUPLEX_FULL == phydev->duplex ? | ||
54 | "Full" : "Half"); | ||
55 | |||
56 | printk("\n"); | ||
57 | } | ||
58 | EXPORT_SYMBOL(phy_print_status); | ||
59 | |||
60 | |||
61 | /* Convenience functions for reading/writing a given PHY | ||
62 | * register. They MUST NOT be called from interrupt context, | ||
63 | * because the bus read/write functions may wait for an interrupt | ||
64 | * to conclude the operation. */ | ||
65 | int phy_read(struct phy_device *phydev, u16 regnum) | ||
66 | { | ||
67 | int retval; | ||
68 | struct mii_bus *bus = phydev->bus; | ||
69 | |||
70 | spin_lock_bh(&bus->mdio_lock); | ||
71 | retval = bus->read(bus, phydev->addr, regnum); | ||
72 | spin_unlock_bh(&bus->mdio_lock); | ||
73 | |||
74 | return retval; | ||
75 | } | ||
76 | EXPORT_SYMBOL(phy_read); | ||
77 | |||
78 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | ||
79 | { | ||
80 | int err; | ||
81 | struct mii_bus *bus = phydev->bus; | ||
82 | |||
83 | spin_lock_bh(&bus->mdio_lock); | ||
84 | err = bus->write(bus, phydev->addr, regnum, val); | ||
85 | spin_unlock_bh(&bus->mdio_lock); | ||
86 | |||
87 | return err; | ||
88 | } | ||
89 | EXPORT_SYMBOL(phy_write); | ||
90 | |||
91 | |||
92 | int phy_clear_interrupt(struct phy_device *phydev) | ||
93 | { | ||
94 | int err = 0; | ||
95 | |||
96 | if (phydev->drv->ack_interrupt) | ||
97 | err = phydev->drv->ack_interrupt(phydev); | ||
98 | |||
99 | return err; | ||
100 | } | ||
101 | |||
102 | |||
103 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | ||
104 | { | ||
105 | int err = 0; | ||
106 | |||
107 | phydev->interrupts = interrupts; | ||
108 | if (phydev->drv->config_intr) | ||
109 | err = phydev->drv->config_intr(phydev); | ||
110 | |||
111 | return err; | ||
112 | } | ||
113 | |||
114 | |||
115 | /* phy_aneg_done | ||
116 | * | ||
117 | * description: Reads the status register and returns 0 either if | ||
118 | * auto-negotiation is incomplete, or if there was an error. | ||
119 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. | ||
120 | */ | ||
121 | static inline int phy_aneg_done(struct phy_device *phydev) | ||
122 | { | ||
123 | int retval; | ||
124 | |||
125 | retval = phy_read(phydev, MII_BMSR); | ||
126 | |||
127 | return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); | ||
128 | } | ||
129 | |||
130 | /* phy_start_aneg | ||
131 | * | ||
132 | * description: Calls the PHY driver's config_aneg, and then | ||
133 | * sets the PHY state to PHY_AN if auto-negotiation is enabled, | ||
134 | * and to PHY_FORCING if auto-negotiation is disabled. Unless | ||
135 | * the PHY is currently HALTED. | ||
136 | */ | ||
137 | int phy_start_aneg(struct phy_device *phydev) | ||
138 | { | ||
139 | int err; | ||
140 | |||
141 | spin_lock(&phydev->lock); | ||
142 | |||
143 | if (AUTONEG_DISABLE == phydev->autoneg) | ||
144 | phy_sanitize_settings(phydev); | ||
145 | |||
146 | err = phydev->drv->config_aneg(phydev); | ||
147 | |||
148 | if (err < 0) | ||
149 | goto out_unlock; | ||
150 | |||
151 | if (phydev->state != PHY_HALTED) { | ||
152 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
153 | phydev->state = PHY_AN; | ||
154 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
155 | } else { | ||
156 | phydev->state = PHY_FORCING; | ||
157 | phydev->link_timeout = PHY_FORCE_TIMEOUT; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | out_unlock: | ||
162 | spin_unlock(&phydev->lock); | ||
163 | return err; | ||
164 | } | ||
165 | EXPORT_SYMBOL(phy_start_aneg); | ||
166 | |||
167 | |||
168 | /* A structure for mapping a particular speed and duplex | ||
169 | * combination to a particular SUPPORTED and ADVERTISED value */ | ||
170 | struct phy_setting { | ||
171 | int speed; | ||
172 | int duplex; | ||
173 | u32 setting; | ||
174 | }; | ||
175 | |||
176 | /* A mapping of all SUPPORTED settings to speed/duplex */ | ||
177 | static struct phy_setting settings[] = { | ||
178 | { | ||
179 | .speed = 10000, | ||
180 | .duplex = DUPLEX_FULL, | ||
181 | .setting = SUPPORTED_10000baseT_Full, | ||
182 | }, | ||
183 | { | ||
184 | .speed = SPEED_1000, | ||
185 | .duplex = DUPLEX_FULL, | ||
186 | .setting = SUPPORTED_1000baseT_Full, | ||
187 | }, | ||
188 | { | ||
189 | .speed = SPEED_1000, | ||
190 | .duplex = DUPLEX_HALF, | ||
191 | .setting = SUPPORTED_1000baseT_Half, | ||
192 | }, | ||
193 | { | ||
194 | .speed = SPEED_100, | ||
195 | .duplex = DUPLEX_FULL, | ||
196 | .setting = SUPPORTED_100baseT_Full, | ||
197 | }, | ||
198 | { | ||
199 | .speed = SPEED_100, | ||
200 | .duplex = DUPLEX_HALF, | ||
201 | .setting = SUPPORTED_100baseT_Half, | ||
202 | }, | ||
203 | { | ||
204 | .speed = SPEED_10, | ||
205 | .duplex = DUPLEX_FULL, | ||
206 | .setting = SUPPORTED_10baseT_Full, | ||
207 | }, | ||
208 | { | ||
209 | .speed = SPEED_10, | ||
210 | .duplex = DUPLEX_HALF, | ||
211 | .setting = SUPPORTED_10baseT_Half, | ||
212 | }, | ||
213 | }; | ||
214 | |||
215 | #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) | ||
216 | |||
217 | /* phy_find_setting | ||
218 | * | ||
219 | * description: Searches the settings array for the setting which | ||
220 | * matches the desired speed and duplex, and returns the index | ||
221 | * of that setting. Returns the index of the last setting if | ||
222 | * none of the others match. | ||
223 | */ | ||
224 | static inline int phy_find_setting(int speed, int duplex) | ||
225 | { | ||
226 | int idx = 0; | ||
227 | |||
228 | while (idx < ARRAY_SIZE(settings) && | ||
229 | (settings[idx].speed != speed || | ||
230 | settings[idx].duplex != duplex)) | ||
231 | idx++; | ||
232 | |||
233 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | ||
234 | } | ||
235 | |||
236 | /* phy_find_valid | ||
237 | * idx: The first index in settings[] to search | ||
238 | * features: A mask of the valid settings | ||
239 | * | ||
240 | * description: Returns the index of the first valid setting less | ||
241 | * than or equal to the one pointed to by idx, as determined by | ||
242 | * the mask in features. Returns the index of the last setting | ||
243 | * if nothing else matches. | ||
244 | */ | ||
245 | static inline int phy_find_valid(int idx, u32 features) | ||
246 | { | ||
247 | while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) | ||
248 | idx++; | ||
249 | |||
250 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | ||
251 | } | ||
252 | |||
253 | /* phy_sanitize_settings | ||
254 | * | ||
255 | * description: Make sure the PHY is set to supported speeds and | ||
256 | * duplexes. Drop down by one in this order: 1000/FULL, | ||
257 | * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF | ||
258 | */ | ||
259 | void phy_sanitize_settings(struct phy_device *phydev) | ||
260 | { | ||
261 | u32 features = phydev->supported; | ||
262 | int idx; | ||
263 | |||
264 | /* Sanitize settings based on PHY capabilities */ | ||
265 | if ((features & SUPPORTED_Autoneg) == 0) | ||
266 | phydev->autoneg = 0; | ||
267 | |||
268 | idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex), | ||
269 | features); | ||
270 | |||
271 | phydev->speed = settings[idx].speed; | ||
272 | phydev->duplex = settings[idx].duplex; | ||
273 | } | ||
274 | EXPORT_SYMBOL(phy_sanitize_settings); | ||
275 | |||
276 | /* phy_force_reduction | ||
277 | * | ||
278 | * description: Reduces the speed/duplex settings by | ||
279 | * one notch. The order is so: | ||
280 | * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, | ||
281 | * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. | ||
282 | */ | ||
283 | static void phy_force_reduction(struct phy_device *phydev) | ||
284 | { | ||
285 | int idx; | ||
286 | |||
287 | idx = phy_find_setting(phydev->speed, phydev->duplex); | ||
288 | |||
289 | idx++; | ||
290 | |||
291 | idx = phy_find_valid(idx, phydev->supported); | ||
292 | |||
293 | phydev->speed = settings[idx].speed; | ||
294 | phydev->duplex = settings[idx].duplex; | ||
295 | |||
296 | pr_info("Trying %d/%s\n", phydev->speed, | ||
297 | DUPLEX_FULL == phydev->duplex ? | ||
298 | "FULL" : "HALF"); | ||
299 | } | ||
300 | |||
301 | /* phy_ethtool_sset: | ||
302 | * A generic ethtool sset function. Handles all the details | ||
303 | * | ||
304 | * A few notes about parameter checking: | ||
305 | * - We don't set port or transceiver, so we don't care what they | ||
306 | * were set to. | ||
307 | * - phy_start_aneg() will make sure forced settings are sane, and | ||
308 | * choose the next best ones from the ones selected, so we don't | ||
309 | * care if ethtool tries to give us bad values | ||
310 | */ | ||
311 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) | ||
312 | { | ||
313 | if (cmd->phy_address != phydev->addr) | ||
314 | return -EINVAL; | ||
315 | |||
316 | /* We make sure that we don't pass unsupported | ||
317 | * values in to the PHY */ | ||
318 | cmd->advertising &= phydev->supported; | ||
319 | |||
320 | /* Verify the settings we care about. */ | ||
321 | if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) | ||
322 | return -EINVAL; | ||
323 | |||
324 | if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) | ||
325 | return -EINVAL; | ||
326 | |||
327 | if (cmd->autoneg == AUTONEG_DISABLE | ||
328 | && ((cmd->speed != SPEED_1000 | ||
329 | && cmd->speed != SPEED_100 | ||
330 | && cmd->speed != SPEED_10) | ||
331 | || (cmd->duplex != DUPLEX_HALF | ||
332 | && cmd->duplex != DUPLEX_FULL))) | ||
333 | return -EINVAL; | ||
334 | |||
335 | phydev->autoneg = cmd->autoneg; | ||
336 | |||
337 | phydev->speed = cmd->speed; | ||
338 | |||
339 | phydev->advertising = cmd->advertising; | ||
340 | |||
341 | if (AUTONEG_ENABLE == cmd->autoneg) | ||
342 | phydev->advertising |= ADVERTISED_Autoneg; | ||
343 | else | ||
344 | phydev->advertising &= ~ADVERTISED_Autoneg; | ||
345 | |||
346 | phydev->duplex = cmd->duplex; | ||
347 | |||
348 | /* Restart the PHY */ | ||
349 | phy_start_aneg(phydev); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | ||
355 | { | ||
356 | cmd->supported = phydev->supported; | ||
357 | |||
358 | cmd->advertising = phydev->advertising; | ||
359 | |||
360 | cmd->speed = phydev->speed; | ||
361 | cmd->duplex = phydev->duplex; | ||
362 | cmd->port = PORT_MII; | ||
363 | cmd->phy_address = phydev->addr; | ||
364 | cmd->transceiver = XCVR_EXTERNAL; | ||
365 | cmd->autoneg = phydev->autoneg; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | |||
371 | /* Note that this function is currently incompatible with the | ||
372 | * PHYCONTROL layer. It changes registers without regard to | ||
373 | * current state. Use at own risk | ||
374 | */ | ||
375 | int phy_mii_ioctl(struct phy_device *phydev, | ||
376 | struct mii_ioctl_data *mii_data, int cmd) | ||
377 | { | ||
378 | u16 val = mii_data->val_in; | ||
379 | |||
380 | switch (cmd) { | ||
381 | case SIOCGMIIPHY: | ||
382 | mii_data->phy_id = phydev->addr; | ||
383 | break; | ||
384 | case SIOCGMIIREG: | ||
385 | mii_data->val_out = phy_read(phydev, mii_data->reg_num); | ||
386 | break; | ||
387 | |||
388 | case SIOCSMIIREG: | ||
389 | if (!capable(CAP_NET_ADMIN)) | ||
390 | return -EPERM; | ||
391 | |||
392 | if (mii_data->phy_id == phydev->addr) { | ||
393 | switch(mii_data->reg_num) { | ||
394 | case MII_BMCR: | ||
395 | if (val & (BMCR_RESET|BMCR_ANENABLE)) | ||
396 | phydev->autoneg = AUTONEG_DISABLE; | ||
397 | else | ||
398 | phydev->autoneg = AUTONEG_ENABLE; | ||
399 | if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) | ||
400 | phydev->duplex = DUPLEX_FULL; | ||
401 | else | ||
402 | phydev->duplex = DUPLEX_HALF; | ||
403 | break; | ||
404 | case MII_ADVERTISE: | ||
405 | phydev->advertising = val; | ||
406 | break; | ||
407 | default: | ||
408 | /* do nothing */ | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | phy_write(phydev, mii_data->reg_num, val); | ||
414 | |||
415 | if (mii_data->reg_num == MII_BMCR | ||
416 | && val & BMCR_RESET | ||
417 | && phydev->drv->config_init) | ||
418 | phydev->drv->config_init(phydev); | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* phy_start_machine: | ||
426 | * | ||
427 | * description: The PHY infrastructure can run a state machine | ||
428 | * which tracks whether the PHY is starting up, negotiating, | ||
429 | * etc. This function starts the timer which tracks the state | ||
430 | * of the PHY. If you want to be notified when the state | ||
431 | * changes, pass in the callback, otherwise, pass NULL. If you | ||
432 | * want to maintain your own state machine, do not call this | ||
433 | * function. */ | ||
434 | void phy_start_machine(struct phy_device *phydev, | ||
435 | void (*handler)(struct net_device *)) | ||
436 | { | ||
437 | phydev->adjust_state = handler; | ||
438 | |||
439 | init_timer(&phydev->phy_timer); | ||
440 | phydev->phy_timer.function = &phy_timer; | ||
441 | phydev->phy_timer.data = (unsigned long) phydev; | ||
442 | mod_timer(&phydev->phy_timer, jiffies + HZ); | ||
443 | } | ||
444 | |||
445 | /* phy_stop_machine | ||
446 | * | ||
447 | * description: Stops the state machine timer, sets the state to | ||
448 | * UP (unless it wasn't up yet), and then frees the interrupt, | ||
449 | * if it is in use. This function must be called BEFORE | ||
450 | * phy_detach. | ||
451 | */ | ||
452 | void phy_stop_machine(struct phy_device *phydev) | ||
453 | { | ||
454 | del_timer_sync(&phydev->phy_timer); | ||
455 | |||
456 | spin_lock(&phydev->lock); | ||
457 | if (phydev->state > PHY_UP) | ||
458 | phydev->state = PHY_UP; | ||
459 | spin_unlock(&phydev->lock); | ||
460 | |||
461 | if (phydev->irq != PHY_POLL) | ||
462 | phy_stop_interrupts(phydev); | ||
463 | |||
464 | phydev->adjust_state = NULL; | ||
465 | } | ||
466 | |||
467 | #ifdef CONFIG_PHYCONTROL | ||
468 | /* phy_error: | ||
469 | * | ||
470 | * Moves the PHY to the HALTED state in response to a read | ||
471 | * or write error, and tells the controller the link is down. | ||
472 | * Must not be called from interrupt context, or while the | ||
473 | * phydev->lock is held. | ||
474 | */ | ||
475 | void phy_error(struct phy_device *phydev) | ||
476 | { | ||
477 | spin_lock(&phydev->lock); | ||
478 | phydev->state = PHY_HALTED; | ||
479 | spin_unlock(&phydev->lock); | ||
480 | } | ||
481 | |||
482 | /* phy_interrupt | ||
483 | * | ||
484 | * description: When a PHY interrupt occurs, the handler disables | ||
485 | * interrupts, and schedules a work task to clear the interrupt. | ||
486 | */ | ||
487 | static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) | ||
488 | { | ||
489 | struct phy_device *phydev = phy_dat; | ||
490 | |||
491 | /* The MDIO bus is not allowed to be written in interrupt | ||
492 | * context, so we need to disable the irq here. A work | ||
493 | * queue will write the PHY to disable and clear the | ||
494 | * interrupt, and then reenable the irq line. */ | ||
495 | disable_irq_nosync(irq); | ||
496 | |||
497 | schedule_work(&phydev->phy_queue); | ||
498 | |||
499 | return IRQ_HANDLED; | ||
500 | } | ||
501 | |||
502 | /* Enable the interrupts from the PHY side */ | ||
503 | int phy_enable_interrupts(struct phy_device *phydev) | ||
504 | { | ||
505 | int err; | ||
506 | |||
507 | err = phy_clear_interrupt(phydev); | ||
508 | |||
509 | if (err < 0) | ||
510 | return err; | ||
511 | |||
512 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); | ||
513 | |||
514 | return err; | ||
515 | } | ||
516 | EXPORT_SYMBOL(phy_enable_interrupts); | ||
517 | |||
518 | /* Disable the PHY interrupts from the PHY side */ | ||
519 | int phy_disable_interrupts(struct phy_device *phydev) | ||
520 | { | ||
521 | int err; | ||
522 | |||
523 | /* Disable PHY interrupts */ | ||
524 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); | ||
525 | |||
526 | if (err) | ||
527 | goto phy_err; | ||
528 | |||
529 | /* Clear the interrupt */ | ||
530 | err = phy_clear_interrupt(phydev); | ||
531 | |||
532 | if (err) | ||
533 | goto phy_err; | ||
534 | |||
535 | return 0; | ||
536 | |||
537 | phy_err: | ||
538 | phy_error(phydev); | ||
539 | |||
540 | return err; | ||
541 | } | ||
542 | EXPORT_SYMBOL(phy_disable_interrupts); | ||
543 | |||
544 | /* phy_start_interrupts | ||
545 | * | ||
546 | * description: Request the interrupt for the given PHY. If | ||
547 | * this fails, then we set irq to PHY_POLL. | ||
548 | * Otherwise, we enable the interrupts in the PHY. | ||
549 | * Returns 0 on success. | ||
550 | * This should only be called with a valid IRQ number. | ||
551 | */ | ||
552 | int phy_start_interrupts(struct phy_device *phydev) | ||
553 | { | ||
554 | int err = 0; | ||
555 | |||
556 | INIT_WORK(&phydev->phy_queue, phy_change, phydev); | ||
557 | |||
558 | if (request_irq(phydev->irq, phy_interrupt, | ||
559 | SA_SHIRQ, | ||
560 | "phy_interrupt", | ||
561 | phydev) < 0) { | ||
562 | printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", | ||
563 | phydev->bus->name, | ||
564 | phydev->irq); | ||
565 | phydev->irq = PHY_POLL; | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | err = phy_enable_interrupts(phydev); | ||
570 | |||
571 | return err; | ||
572 | } | ||
573 | EXPORT_SYMBOL(phy_start_interrupts); | ||
574 | |||
575 | int phy_stop_interrupts(struct phy_device *phydev) | ||
576 | { | ||
577 | int err; | ||
578 | |||
579 | err = phy_disable_interrupts(phydev); | ||
580 | |||
581 | if (err) | ||
582 | phy_error(phydev); | ||
583 | |||
584 | free_irq(phydev->irq, phydev); | ||
585 | |||
586 | return err; | ||
587 | } | ||
588 | EXPORT_SYMBOL(phy_stop_interrupts); | ||
589 | |||
590 | |||
591 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | ||
592 | static void phy_change(void *data) | ||
593 | { | ||
594 | int err; | ||
595 | struct phy_device *phydev = data; | ||
596 | |||
597 | err = phy_disable_interrupts(phydev); | ||
598 | |||
599 | if (err) | ||
600 | goto phy_err; | ||
601 | |||
602 | spin_lock(&phydev->lock); | ||
603 | if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) | ||
604 | phydev->state = PHY_CHANGELINK; | ||
605 | spin_unlock(&phydev->lock); | ||
606 | |||
607 | enable_irq(phydev->irq); | ||
608 | |||
609 | /* Reenable interrupts */ | ||
610 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); | ||
611 | |||
612 | if (err) | ||
613 | goto irq_enable_err; | ||
614 | |||
615 | return; | ||
616 | |||
617 | irq_enable_err: | ||
618 | disable_irq(phydev->irq); | ||
619 | phy_err: | ||
620 | phy_error(phydev); | ||
621 | } | ||
622 | |||
623 | /* Bring down the PHY link, and stop checking the status. */ | ||
624 | void phy_stop(struct phy_device *phydev) | ||
625 | { | ||
626 | spin_lock(&phydev->lock); | ||
627 | |||
628 | if (PHY_HALTED == phydev->state) | ||
629 | goto out_unlock; | ||
630 | |||
631 | if (phydev->irq != PHY_POLL) { | ||
632 | /* Clear any pending interrupts */ | ||
633 | phy_clear_interrupt(phydev); | ||
634 | |||
635 | /* Disable PHY Interrupts */ | ||
636 | phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); | ||
637 | } | ||
638 | |||
639 | phydev->state = PHY_HALTED; | ||
640 | |||
641 | out_unlock: | ||
642 | spin_unlock(&phydev->lock); | ||
643 | } | ||
644 | |||
645 | |||
646 | /* phy_start | ||
647 | * | ||
648 | * description: Indicates the attached device's readiness to | ||
649 | * handle PHY-related work. Used during startup to start the | ||
650 | * PHY, and after a call to phy_stop() to resume operation. | ||
651 | * Also used to indicate the MDIO bus has cleared an error | ||
652 | * condition. | ||
653 | */ | ||
654 | void phy_start(struct phy_device *phydev) | ||
655 | { | ||
656 | spin_lock(&phydev->lock); | ||
657 | |||
658 | switch (phydev->state) { | ||
659 | case PHY_STARTING: | ||
660 | phydev->state = PHY_PENDING; | ||
661 | break; | ||
662 | case PHY_READY: | ||
663 | phydev->state = PHY_UP; | ||
664 | break; | ||
665 | case PHY_HALTED: | ||
666 | phydev->state = PHY_RESUMING; | ||
667 | default: | ||
668 | break; | ||
669 | } | ||
670 | spin_unlock(&phydev->lock); | ||
671 | } | ||
672 | EXPORT_SYMBOL(phy_stop); | ||
673 | EXPORT_SYMBOL(phy_start); | ||
674 | |||
675 | /* PHY timer which handles the state machine */ | ||
676 | static void phy_timer(unsigned long data) | ||
677 | { | ||
678 | struct phy_device *phydev = (struct phy_device *)data; | ||
679 | int needs_aneg = 0; | ||
680 | int err = 0; | ||
681 | |||
682 | spin_lock(&phydev->lock); | ||
683 | |||
684 | if (phydev->adjust_state) | ||
685 | phydev->adjust_state(phydev->attached_dev); | ||
686 | |||
687 | switch(phydev->state) { | ||
688 | case PHY_DOWN: | ||
689 | case PHY_STARTING: | ||
690 | case PHY_READY: | ||
691 | case PHY_PENDING: | ||
692 | break; | ||
693 | case PHY_UP: | ||
694 | needs_aneg = 1; | ||
695 | |||
696 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
697 | |||
698 | break; | ||
699 | case PHY_AN: | ||
700 | /* Check if negotiation is done. Break | ||
701 | * if there's an error */ | ||
702 | err = phy_aneg_done(phydev); | ||
703 | if (err < 0) | ||
704 | break; | ||
705 | |||
706 | /* If auto-negotiation is done, we change to | ||
707 | * either RUNNING, or NOLINK */ | ||
708 | if (err > 0) { | ||
709 | err = phy_read_status(phydev); | ||
710 | |||
711 | if (err) | ||
712 | break; | ||
713 | |||
714 | if (phydev->link) { | ||
715 | phydev->state = PHY_RUNNING; | ||
716 | netif_carrier_on(phydev->attached_dev); | ||
717 | } else { | ||
718 | phydev->state = PHY_NOLINK; | ||
719 | netif_carrier_off(phydev->attached_dev); | ||
720 | } | ||
721 | |||
722 | phydev->adjust_link(phydev->attached_dev); | ||
723 | |||
724 | } else if (0 == phydev->link_timeout--) { | ||
725 | /* The counter expired, so either we | ||
726 | * switch to forced mode, or the | ||
727 | * magic_aneg bit exists, and we try aneg | ||
728 | * again */ | ||
729 | if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { | ||
730 | int idx; | ||
731 | |||
732 | /* We'll start from the | ||
733 | * fastest speed, and work | ||
734 | * our way down */ | ||
735 | idx = phy_find_valid(0, | ||
736 | phydev->supported); | ||
737 | |||
738 | phydev->speed = settings[idx].speed; | ||
739 | phydev->duplex = settings[idx].duplex; | ||
740 | |||
741 | phydev->autoneg = AUTONEG_DISABLE; | ||
742 | phydev->state = PHY_FORCING; | ||
743 | phydev->link_timeout = | ||
744 | PHY_FORCE_TIMEOUT; | ||
745 | |||
746 | pr_info("Trying %d/%s\n", | ||
747 | phydev->speed, | ||
748 | DUPLEX_FULL == | ||
749 | phydev->duplex ? | ||
750 | "FULL" : "HALF"); | ||
751 | } | ||
752 | |||
753 | needs_aneg = 1; | ||
754 | } | ||
755 | break; | ||
756 | case PHY_NOLINK: | ||
757 | err = phy_read_status(phydev); | ||
758 | |||
759 | if (err) | ||
760 | break; | ||
761 | |||
762 | if (phydev->link) { | ||
763 | phydev->state = PHY_RUNNING; | ||
764 | netif_carrier_on(phydev->attached_dev); | ||
765 | phydev->adjust_link(phydev->attached_dev); | ||
766 | } | ||
767 | break; | ||
768 | case PHY_FORCING: | ||
769 | err = phy_read_status(phydev); | ||
770 | |||
771 | if (err) | ||
772 | break; | ||
773 | |||
774 | if (phydev->link) { | ||
775 | phydev->state = PHY_RUNNING; | ||
776 | netif_carrier_on(phydev->attached_dev); | ||
777 | } else { | ||
778 | if (0 == phydev->link_timeout--) { | ||
779 | phy_force_reduction(phydev); | ||
780 | needs_aneg = 1; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | phydev->adjust_link(phydev->attached_dev); | ||
785 | break; | ||
786 | case PHY_RUNNING: | ||
787 | /* Only register a CHANGE if we are | ||
788 | * polling */ | ||
789 | if (PHY_POLL == phydev->irq) | ||
790 | phydev->state = PHY_CHANGELINK; | ||
791 | break; | ||
792 | case PHY_CHANGELINK: | ||
793 | err = phy_read_status(phydev); | ||
794 | |||
795 | if (err) | ||
796 | break; | ||
797 | |||
798 | if (phydev->link) { | ||
799 | phydev->state = PHY_RUNNING; | ||
800 | netif_carrier_on(phydev->attached_dev); | ||
801 | } else { | ||
802 | phydev->state = PHY_NOLINK; | ||
803 | netif_carrier_off(phydev->attached_dev); | ||
804 | } | ||
805 | |||
806 | phydev->adjust_link(phydev->attached_dev); | ||
807 | |||
808 | if (PHY_POLL != phydev->irq) | ||
809 | err = phy_config_interrupt(phydev, | ||
810 | PHY_INTERRUPT_ENABLED); | ||
811 | break; | ||
812 | case PHY_HALTED: | ||
813 | if (phydev->link) { | ||
814 | phydev->link = 0; | ||
815 | netif_carrier_off(phydev->attached_dev); | ||
816 | phydev->adjust_link(phydev->attached_dev); | ||
817 | } | ||
818 | break; | ||
819 | case PHY_RESUMING: | ||
820 | |||
821 | err = phy_clear_interrupt(phydev); | ||
822 | |||
823 | if (err) | ||
824 | break; | ||
825 | |||
826 | err = phy_config_interrupt(phydev, | ||
827 | PHY_INTERRUPT_ENABLED); | ||
828 | |||
829 | if (err) | ||
830 | break; | ||
831 | |||
832 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
833 | err = phy_aneg_done(phydev); | ||
834 | if (err < 0) | ||
835 | break; | ||
836 | |||
837 | /* err > 0 if AN is done. | ||
838 | * Otherwise, it's 0, and we're | ||
839 | * still waiting for AN */ | ||
840 | if (err > 0) { | ||
841 | phydev->state = PHY_RUNNING; | ||
842 | } else { | ||
843 | phydev->state = PHY_AN; | ||
844 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
845 | } | ||
846 | } else | ||
847 | phydev->state = PHY_RUNNING; | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | spin_unlock(&phydev->lock); | ||
852 | |||
853 | if (needs_aneg) | ||
854 | err = phy_start_aneg(phydev); | ||
855 | |||
856 | if (err < 0) | ||
857 | phy_error(phydev); | ||
858 | |||
859 | mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); | ||
860 | } | ||
861 | |||
862 | #endif /* CONFIG_PHYCONTROL */ | ||
diff --git a/drivers/net/phy/phy.c.orig b/drivers/net/phy/phy.c.orig new file mode 100644 index 000000000000..6af17cec9ace --- /dev/null +++ b/drivers/net/phy/phy.c.orig | |||
@@ -0,0 +1,860 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/phy.c | ||
3 | * | ||
4 | * Framework for configuring and reading PHY devices | ||
5 | * Based on code in sungem_phy.c and gianfar_phy.c | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * | ||
9 | * Copyright (c) 2004 Freescale Semiconductor, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/phy.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | static void phy_change(void *data); | ||
43 | static void phy_timer(unsigned long data); | ||
44 | |||
45 | /* Convenience function to print out the current phy status | ||
46 | */ | ||
47 | void phy_print_status(struct phy_device *phydev) | ||
48 | { | ||
49 | pr_info("%s: Link is %s", phydev->dev.bus_id, | ||
50 | phydev->link ? "Up" : "Down"); | ||
51 | if (phydev->link) | ||
52 | printk(" - %d/%s", phydev->speed, | ||
53 | DUPLEX_FULL == phydev->duplex ? | ||
54 | "Full" : "Half"); | ||
55 | |||
56 | printk("\n"); | ||
57 | } | ||
58 | EXPORT_SYMBOL(phy_print_status); | ||
59 | |||
60 | |||
61 | /* Convenience functions for reading/writing a given PHY | ||
62 | * register. They MUST NOT be called from interrupt context, | ||
63 | * because the bus read/write functions may wait for an interrupt | ||
64 | * to conclude the operation. */ | ||
65 | int phy_read(struct phy_device *phydev, u16 regnum) | ||
66 | { | ||
67 | int retval; | ||
68 | struct mii_bus *bus = phydev->bus; | ||
69 | |||
70 | spin_lock_bh(&bus->mdio_lock); | ||
71 | retval = bus->read(bus, phydev->addr, regnum); | ||
72 | spin_unlock_bh(&bus->mdio_lock); | ||
73 | |||
74 | return retval; | ||
75 | } | ||
76 | EXPORT_SYMBOL(phy_read); | ||
77 | |||
78 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | ||
79 | { | ||
80 | int err; | ||
81 | struct mii_bus *bus = phydev->bus; | ||
82 | |||
83 | spin_lock_bh(&bus->mdio_lock); | ||
84 | err = bus->write(bus, phydev->addr, regnum, val); | ||
85 | spin_unlock_bh(&bus->mdio_lock); | ||
86 | |||
87 | return err; | ||
88 | } | ||
89 | EXPORT_SYMBOL(phy_write); | ||
90 | |||
91 | |||
92 | int phy_clear_interrupt(struct phy_device *phydev) | ||
93 | { | ||
94 | int err = 0; | ||
95 | |||
96 | if (phydev->drv->ack_interrupt) | ||
97 | err = phydev->drv->ack_interrupt(phydev); | ||
98 | |||
99 | return err; | ||
100 | } | ||
101 | |||
102 | |||
103 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | ||
104 | { | ||
105 | int err = 0; | ||
106 | |||
107 | phydev->interrupts = interrupts; | ||
108 | if (phydev->drv->config_intr) | ||
109 | err = phydev->drv->config_intr(phydev); | ||
110 | |||
111 | return err; | ||
112 | } | ||
113 | |||
114 | |||
115 | /* phy_aneg_done | ||
116 | * | ||
117 | * description: Reads the status register and returns 0 either if | ||
118 | * auto-negotiation is incomplete, or if there was an error. | ||
119 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. | ||
120 | */ | ||
121 | static inline int phy_aneg_done(struct phy_device *phydev) | ||
122 | { | ||
123 | int retval; | ||
124 | |||
125 | retval = phy_read(phydev, MII_BMSR); | ||
126 | |||
127 | return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); | ||
128 | } | ||
129 | |||
130 | /* phy_start_aneg | ||
131 | * | ||
132 | * description: Calls the PHY driver's config_aneg, and then | ||
133 | * sets the PHY state to PHY_AN if auto-negotiation is enabled, | ||
134 | * and to PHY_FORCING if auto-negotiation is disabled. Unless | ||
135 | * the PHY is currently HALTED. | ||
136 | */ | ||
137 | int phy_start_aneg(struct phy_device *phydev) | ||
138 | { | ||
139 | int err; | ||
140 | |||
141 | spin_lock(&phydev->lock); | ||
142 | |||
143 | if (AUTONEG_DISABLE == phydev->autoneg) | ||
144 | phy_sanitize_settings(phydev); | ||
145 | |||
146 | err = phydev->drv->config_aneg(phydev); | ||
147 | |||
148 | if (err < 0) | ||
149 | goto out_unlock; | ||
150 | |||
151 | if (phydev->state != PHY_HALTED) { | ||
152 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
153 | phydev->state = PHY_AN; | ||
154 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
155 | } else { | ||
156 | phydev->state = PHY_FORCING; | ||
157 | phydev->link_timeout = PHY_FORCE_TIMEOUT; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | out_unlock: | ||
162 | spin_unlock(&phydev->lock); | ||
163 | return err; | ||
164 | } | ||
165 | EXPORT_SYMBOL(phy_start_aneg); | ||
166 | |||
167 | |||
168 | /* A structure for mapping a particular speed and duplex | ||
169 | * combination to a particular SUPPORTED and ADVERTISED value */ | ||
170 | struct phy_setting { | ||
171 | int speed; | ||
172 | int duplex; | ||
173 | u32 setting; | ||
174 | }; | ||
175 | |||
176 | /* A mapping of all SUPPORTED settings to speed/duplex */ | ||
177 | static struct phy_setting settings[] = { | ||
178 | { | ||
179 | .speed = 10000, | ||
180 | .duplex = DUPLEX_FULL, | ||
181 | .setting = SUPPORTED_10000baseT_Full, | ||
182 | }, | ||
183 | { | ||
184 | .speed = SPEED_1000, | ||
185 | .duplex = DUPLEX_FULL, | ||
186 | .setting = SUPPORTED_1000baseT_Full, | ||
187 | }, | ||
188 | { | ||
189 | .speed = SPEED_1000, | ||
190 | .duplex = DUPLEX_HALF, | ||
191 | .setting = SUPPORTED_1000baseT_Half, | ||
192 | }, | ||
193 | { | ||
194 | .speed = SPEED_100, | ||
195 | .duplex = DUPLEX_FULL, | ||
196 | .setting = SUPPORTED_100baseT_Full, | ||
197 | }, | ||
198 | { | ||
199 | .speed = SPEED_100, | ||
200 | .duplex = DUPLEX_HALF, | ||
201 | .setting = SUPPORTED_100baseT_Half, | ||
202 | }, | ||
203 | { | ||
204 | .speed = SPEED_10, | ||
205 | .duplex = DUPLEX_FULL, | ||
206 | .setting = SUPPORTED_10baseT_Full, | ||
207 | }, | ||
208 | { | ||
209 | .speed = SPEED_10, | ||
210 | .duplex = DUPLEX_HALF, | ||
211 | .setting = SUPPORTED_10baseT_Half, | ||
212 | }, | ||
213 | }; | ||
214 | |||
215 | #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) | ||
216 | |||
217 | /* phy_find_setting | ||
218 | * | ||
219 | * description: Searches the settings array for the setting which | ||
220 | * matches the desired speed and duplex, and returns the index | ||
221 | * of that setting. Returns the index of the last setting if | ||
222 | * none of the others match. | ||
223 | */ | ||
224 | static inline int phy_find_setting(int speed, int duplex) | ||
225 | { | ||
226 | int idx = 0; | ||
227 | |||
228 | while (idx < ARRAY_SIZE(settings) && | ||
229 | (settings[idx].speed != speed || | ||
230 | settings[idx].duplex != duplex)) | ||
231 | idx++; | ||
232 | |||
233 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | ||
234 | } | ||
235 | |||
236 | /* phy_find_valid | ||
237 | * idx: The first index in settings[] to search | ||
238 | * features: A mask of the valid settings | ||
239 | * | ||
240 | * description: Returns the index of the first valid setting less | ||
241 | * than or equal to the one pointed to by idx, as determined by | ||
242 | * the mask in features. Returns the index of the last setting | ||
243 | * if nothing else matches. | ||
244 | */ | ||
245 | static inline int phy_find_valid(int idx, u32 features) | ||
246 | { | ||
247 | while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) | ||
248 | idx++; | ||
249 | |||
250 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | ||
251 | } | ||
252 | |||
253 | /* phy_sanitize_settings | ||
254 | * | ||
255 | * description: Make sure the PHY is set to supported speeds and | ||
256 | * duplexes. Drop down by one in this order: 1000/FULL, | ||
257 | * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF | ||
258 | */ | ||
259 | void phy_sanitize_settings(struct phy_device *phydev) | ||
260 | { | ||
261 | u32 features = phydev->supported; | ||
262 | int idx; | ||
263 | |||
264 | /* Sanitize settings based on PHY capabilities */ | ||
265 | if ((features & SUPPORTED_Autoneg) == 0) | ||
266 | phydev->autoneg = 0; | ||
267 | |||
268 | idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex), | ||
269 | features); | ||
270 | |||
271 | phydev->speed = settings[idx].speed; | ||
272 | phydev->duplex = settings[idx].duplex; | ||
273 | } | ||
274 | EXPORT_SYMBOL(phy_sanitize_settings); | ||
275 | |||
276 | /* phy_force_reduction | ||
277 | * | ||
278 | * description: Reduces the speed/duplex settings by | ||
279 | * one notch. The order is so: | ||
280 | * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, | ||
281 | * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. | ||
282 | */ | ||
283 | static void phy_force_reduction(struct phy_device *phydev) | ||
284 | { | ||
285 | int idx; | ||
286 | |||
287 | idx = phy_find_setting(phydev->speed, phydev->duplex); | ||
288 | |||
289 | idx++; | ||
290 | |||
291 | idx = phy_find_valid(idx, phydev->supported); | ||
292 | |||
293 | phydev->speed = settings[idx].speed; | ||
294 | phydev->duplex = settings[idx].duplex; | ||
295 | |||
296 | pr_info("Trying %d/%s\n", phydev->speed, | ||
297 | DUPLEX_FULL == phydev->duplex ? | ||
298 | "FULL" : "HALF"); | ||
299 | } | ||
300 | |||
301 | /* phy_ethtool_sset: | ||
302 | * A generic ethtool sset function. Handles all the details | ||
303 | * | ||
304 | * A few notes about parameter checking: | ||
305 | * - We don't set port or transceiver, so we don't care what they | ||
306 | * were set to. | ||
307 | * - phy_start_aneg() will make sure forced settings are sane, and | ||
308 | * choose the next best ones from the ones selected, so we don't | ||
309 | * care if ethtool tries to give us bad values | ||
310 | */ | ||
311 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) | ||
312 | { | ||
313 | if (cmd->phy_address != phydev->addr) | ||
314 | return -EINVAL; | ||
315 | |||
316 | /* We make sure that we don't pass unsupported | ||
317 | * values in to the PHY */ | ||
318 | cmd->advertising &= phydev->supported; | ||
319 | |||
320 | /* Verify the settings we care about. */ | ||
321 | if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) | ||
322 | return -EINVAL; | ||
323 | |||
324 | if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) | ||
325 | return -EINVAL; | ||
326 | |||
327 | if (cmd->autoneg == AUTONEG_DISABLE | ||
328 | && ((cmd->speed != SPEED_1000 | ||
329 | && cmd->speed != SPEED_100 | ||
330 | && cmd->speed != SPEED_10) | ||
331 | || (cmd->duplex != DUPLEX_HALF | ||
332 | && cmd->duplex != DUPLEX_FULL))) | ||
333 | return -EINVAL; | ||
334 | |||
335 | phydev->autoneg = cmd->autoneg; | ||
336 | |||
337 | phydev->speed = cmd->speed; | ||
338 | |||
339 | phydev->advertising = cmd->advertising; | ||
340 | |||
341 | if (AUTONEG_ENABLE == cmd->autoneg) | ||
342 | phydev->advertising |= ADVERTISED_Autoneg; | ||
343 | else | ||
344 | phydev->advertising &= ~ADVERTISED_Autoneg; | ||
345 | |||
346 | phydev->duplex = cmd->duplex; | ||
347 | |||
348 | /* Restart the PHY */ | ||
349 | phy_start_aneg(phydev); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | ||
355 | { | ||
356 | cmd->supported = phydev->supported; | ||
357 | |||
358 | cmd->advertising = phydev->advertising; | ||
359 | |||
360 | cmd->speed = phydev->speed; | ||
361 | cmd->duplex = phydev->duplex; | ||
362 | cmd->port = PORT_MII; | ||
363 | cmd->phy_address = phydev->addr; | ||
364 | cmd->transceiver = XCVR_EXTERNAL; | ||
365 | cmd->autoneg = phydev->autoneg; | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | |||
371 | /* Note that this function is currently incompatible with the | ||
372 | * PHYCONTROL layer. It changes registers without regard to | ||
373 | * current state. Use at own risk | ||
374 | */ | ||
375 | int phy_mii_ioctl(struct phy_device *phydev, | ||
376 | struct mii_ioctl_data *mii_data, int cmd) | ||
377 | { | ||
378 | u16 val = mii_data->val_in; | ||
379 | |||
380 | switch (cmd) { | ||
381 | case SIOCGMIIPHY: | ||
382 | mii_data->phy_id = phydev->addr; | ||
383 | break; | ||
384 | case SIOCGMIIREG: | ||
385 | mii_data->val_out = phy_read(phydev, mii_data->reg_num); | ||
386 | break; | ||
387 | |||
388 | case SIOCSMIIREG: | ||
389 | if (!capable(CAP_NET_ADMIN)) | ||
390 | return -EPERM; | ||
391 | |||
392 | if (mii_data->phy_id == phydev->addr) { | ||
393 | switch(mii_data->reg_num) { | ||
394 | case MII_BMCR: | ||
395 | if (val & (BMCR_RESET|BMCR_ANENABLE)) | ||
396 | phydev->autoneg = AUTONEG_DISABLE; | ||
397 | else | ||
398 | phydev->autoneg = AUTONEG_ENABLE; | ||
399 | if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) | ||
400 | phydev->duplex = DUPLEX_FULL; | ||
401 | else | ||
402 | phydev->duplex = DUPLEX_HALF; | ||
403 | break; | ||
404 | case MII_ADVERTISE: | ||
405 | phydev->advertising = val; | ||
406 | break; | ||
407 | default: | ||
408 | /* do nothing */ | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | phy_write(phydev, mii_data->reg_num, val); | ||
414 | |||
415 | if (mii_data->reg_num == MII_BMCR | ||
416 | && val & BMCR_RESET | ||
417 | && phydev->drv->config_init) | ||
418 | phydev->drv->config_init(phydev); | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* phy_start_machine: | ||
426 | * | ||
427 | * description: The PHY infrastructure can run a state machine | ||
428 | * which tracks whether the PHY is starting up, negotiating, | ||
429 | * etc. This function starts the timer which tracks the state | ||
430 | * of the PHY. If you want to be notified when the state | ||
431 | * changes, pass in the callback, otherwise, pass NULL. If you | ||
432 | * want to maintain your own state machine, do not call this | ||
433 | * function. */ | ||
434 | void phy_start_machine(struct phy_device *phydev, | ||
435 | void (*handler)(struct net_device *)) | ||
436 | { | ||
437 | phydev->adjust_state = handler; | ||
438 | |||
439 | init_timer(&phydev->phy_timer); | ||
440 | phydev->phy_timer.function = &phy_timer; | ||
441 | phydev->phy_timer.data = (unsigned long) phydev; | ||
442 | mod_timer(&phydev->phy_timer, jiffies + HZ); | ||
443 | } | ||
444 | |||
445 | /* phy_stop_machine | ||
446 | * | ||
447 | * description: Stops the state machine timer, sets the state to | ||
448 | * UP (unless it wasn't up yet), and then frees the interrupt, | ||
449 | * if it is in use. This function must be called BEFORE | ||
450 | * phy_detach. | ||
451 | */ | ||
452 | void phy_stop_machine(struct phy_device *phydev) | ||
453 | { | ||
454 | del_timer_sync(&phydev->phy_timer); | ||
455 | |||
456 | spin_lock(&phydev->lock); | ||
457 | if (phydev->state > PHY_UP) | ||
458 | phydev->state = PHY_UP; | ||
459 | spin_unlock(&phydev->lock); | ||
460 | |||
461 | if (phydev->irq != PHY_POLL) | ||
462 | phy_stop_interrupts(phydev); | ||
463 | |||
464 | phydev->adjust_state = NULL; | ||
465 | } | ||
466 | |||
467 | #ifdef CONFIG_PHYCONTROL | ||
468 | /* phy_error: | ||
469 | * | ||
470 | * Moves the PHY to the HALTED state in response to a read | ||
471 | * or write error, and tells the controller the link is down. | ||
472 | * Must not be called from interrupt context, or while the | ||
473 | * phydev->lock is held. | ||
474 | */ | ||
475 | void phy_error(struct phy_device *phydev) | ||
476 | { | ||
477 | spin_lock(&phydev->lock); | ||
478 | phydev->state = PHY_HALTED; | ||
479 | spin_unlock(&phydev->lock); | ||
480 | } | ||
481 | |||
482 | /* phy_interrupt | ||
483 | * | ||
484 | * description: When a PHY interrupt occurs, the handler disables | ||
485 | * interrupts, and schedules a work task to clear the interrupt. | ||
486 | */ | ||
487 | static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) | ||
488 | { | ||
489 | struct phy_device *phydev = phy_dat; | ||
490 | |||
491 | /* The MDIO bus is not allowed to be written in interrupt | ||
492 | * context, so we need to disable the irq here. A work | ||
493 | * queue will write the PHY to disable and clear the | ||
494 | * interrupt, and then reenable the irq line. */ | ||
495 | disable_irq_nosync(irq); | ||
496 | |||
497 | schedule_work(&phydev->phy_queue); | ||
498 | |||
499 | return IRQ_HANDLED; | ||
500 | } | ||
501 | |||
502 | /* Enable the interrupts from the PHY side */ | ||
503 | int phy_enable_interrupts(struct phy_device *phydev) | ||
504 | { | ||
505 | int err; | ||
506 | |||
507 | err = phy_clear_interrupt(phydev); | ||
508 | |||
509 | if (err < 0) | ||
510 | return err; | ||
511 | |||
512 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); | ||
513 | |||
514 | return err; | ||
515 | } | ||
516 | |||
517 | /* Disable the PHY interrupts from the PHY side */ | ||
518 | int phy_disable_interrupts(struct phy_device *phydev) | ||
519 | { | ||
520 | int err; | ||
521 | |||
522 | /* Disable PHY interrupts */ | ||
523 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); | ||
524 | |||
525 | if (err) | ||
526 | goto phy_err; | ||
527 | |||
528 | /* Clear the interrupt */ | ||
529 | err = phy_clear_interrupt(phydev); | ||
530 | |||
531 | if (err) | ||
532 | goto phy_err; | ||
533 | |||
534 | return 0; | ||
535 | |||
536 | phy_err: | ||
537 | phy_error(phydev); | ||
538 | |||
539 | return err; | ||
540 | } | ||
541 | |||
542 | /* phy_start_interrupts | ||
543 | * | ||
544 | * description: Request the interrupt for the given PHY. If | ||
545 | * this fails, then we set irq to PHY_POLL. | ||
546 | * Otherwise, we enable the interrupts in the PHY. | ||
547 | * Returns 0 on success. | ||
548 | * This should only be called with a valid IRQ number. | ||
549 | */ | ||
550 | int phy_start_interrupts(struct phy_device *phydev) | ||
551 | { | ||
552 | int err = 0; | ||
553 | |||
554 | INIT_WORK(&phydev->phy_queue, phy_change, phydev); | ||
555 | |||
556 | if (request_irq(phydev->irq, phy_interrupt, | ||
557 | SA_SHIRQ, | ||
558 | "phy_interrupt", | ||
559 | phydev) < 0) { | ||
560 | printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", | ||
561 | phydev->bus->name, | ||
562 | phydev->irq); | ||
563 | phydev->irq = PHY_POLL; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | err = phy_enable_interrupts(phydev); | ||
568 | |||
569 | return err; | ||
570 | } | ||
571 | EXPORT_SYMBOL(phy_start_interrupts); | ||
572 | |||
573 | int phy_stop_interrupts(struct phy_device *phydev) | ||
574 | { | ||
575 | int err; | ||
576 | |||
577 | err = phy_disable_interrupts(phydev); | ||
578 | |||
579 | if (err) | ||
580 | phy_error(phydev); | ||
581 | |||
582 | free_irq(phydev->irq, phydev); | ||
583 | |||
584 | return err; | ||
585 | } | ||
586 | EXPORT_SYMBOL(phy_stop_interrupts); | ||
587 | |||
588 | |||
589 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | ||
590 | static void phy_change(void *data) | ||
591 | { | ||
592 | int err; | ||
593 | struct phy_device *phydev = data; | ||
594 | |||
595 | err = phy_disable_interrupts(phydev); | ||
596 | |||
597 | if (err) | ||
598 | goto phy_err; | ||
599 | |||
600 | spin_lock(&phydev->lock); | ||
601 | if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) | ||
602 | phydev->state = PHY_CHANGELINK; | ||
603 | spin_unlock(&phydev->lock); | ||
604 | |||
605 | enable_irq(phydev->irq); | ||
606 | |||
607 | /* Reenable interrupts */ | ||
608 | err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); | ||
609 | |||
610 | if (err) | ||
611 | goto irq_enable_err; | ||
612 | |||
613 | return; | ||
614 | |||
615 | irq_enable_err: | ||
616 | disable_irq(phydev->irq); | ||
617 | phy_err: | ||
618 | phy_error(phydev); | ||
619 | } | ||
620 | |||
621 | /* Bring down the PHY link, and stop checking the status. */ | ||
622 | void phy_stop(struct phy_device *phydev) | ||
623 | { | ||
624 | spin_lock(&phydev->lock); | ||
625 | |||
626 | if (PHY_HALTED == phydev->state) | ||
627 | goto out_unlock; | ||
628 | |||
629 | if (phydev->irq != PHY_POLL) { | ||
630 | /* Clear any pending interrupts */ | ||
631 | phy_clear_interrupt(phydev); | ||
632 | |||
633 | /* Disable PHY Interrupts */ | ||
634 | phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); | ||
635 | } | ||
636 | |||
637 | phydev->state = PHY_HALTED; | ||
638 | |||
639 | out_unlock: | ||
640 | spin_unlock(&phydev->lock); | ||
641 | } | ||
642 | |||
643 | |||
644 | /* phy_start | ||
645 | * | ||
646 | * description: Indicates the attached device's readiness to | ||
647 | * handle PHY-related work. Used during startup to start the | ||
648 | * PHY, and after a call to phy_stop() to resume operation. | ||
649 | * Also used to indicate the MDIO bus has cleared an error | ||
650 | * condition. | ||
651 | */ | ||
652 | void phy_start(struct phy_device *phydev) | ||
653 | { | ||
654 | spin_lock(&phydev->lock); | ||
655 | |||
656 | switch (phydev->state) { | ||
657 | case PHY_STARTING: | ||
658 | phydev->state = PHY_PENDING; | ||
659 | break; | ||
660 | case PHY_READY: | ||
661 | phydev->state = PHY_UP; | ||
662 | break; | ||
663 | case PHY_HALTED: | ||
664 | phydev->state = PHY_RESUMING; | ||
665 | default: | ||
666 | break; | ||
667 | } | ||
668 | spin_unlock(&phydev->lock); | ||
669 | } | ||
670 | EXPORT_SYMBOL(phy_stop); | ||
671 | EXPORT_SYMBOL(phy_start); | ||
672 | |||
673 | /* PHY timer which handles the state machine */ | ||
674 | static void phy_timer(unsigned long data) | ||
675 | { | ||
676 | struct phy_device *phydev = (struct phy_device *)data; | ||
677 | int needs_aneg = 0; | ||
678 | int err = 0; | ||
679 | |||
680 | spin_lock(&phydev->lock); | ||
681 | |||
682 | if (phydev->adjust_state) | ||
683 | phydev->adjust_state(phydev->attached_dev); | ||
684 | |||
685 | switch(phydev->state) { | ||
686 | case PHY_DOWN: | ||
687 | case PHY_STARTING: | ||
688 | case PHY_READY: | ||
689 | case PHY_PENDING: | ||
690 | break; | ||
691 | case PHY_UP: | ||
692 | needs_aneg = 1; | ||
693 | |||
694 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
695 | |||
696 | break; | ||
697 | case PHY_AN: | ||
698 | /* Check if negotiation is done. Break | ||
699 | * if there's an error */ | ||
700 | err = phy_aneg_done(phydev); | ||
701 | if (err < 0) | ||
702 | break; | ||
703 | |||
704 | /* If auto-negotiation is done, we change to | ||
705 | * either RUNNING, or NOLINK */ | ||
706 | if (err > 0) { | ||
707 | err = phy_read_status(phydev); | ||
708 | |||
709 | if (err) | ||
710 | break; | ||
711 | |||
712 | if (phydev->link) { | ||
713 | phydev->state = PHY_RUNNING; | ||
714 | netif_carrier_on(phydev->attached_dev); | ||
715 | } else { | ||
716 | phydev->state = PHY_NOLINK; | ||
717 | netif_carrier_off(phydev->attached_dev); | ||
718 | } | ||
719 | |||
720 | phydev->adjust_link(phydev->attached_dev); | ||
721 | |||
722 | } else if (0 == phydev->link_timeout--) { | ||
723 | /* The counter expired, so either we | ||
724 | * switch to forced mode, or the | ||
725 | * magic_aneg bit exists, and we try aneg | ||
726 | * again */ | ||
727 | if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { | ||
728 | int idx; | ||
729 | |||
730 | /* We'll start from the | ||
731 | * fastest speed, and work | ||
732 | * our way down */ | ||
733 | idx = phy_find_valid(0, | ||
734 | phydev->supported); | ||
735 | |||
736 | phydev->speed = settings[idx].speed; | ||
737 | phydev->duplex = settings[idx].duplex; | ||
738 | |||
739 | phydev->autoneg = AUTONEG_DISABLE; | ||
740 | phydev->state = PHY_FORCING; | ||
741 | phydev->link_timeout = | ||
742 | PHY_FORCE_TIMEOUT; | ||
743 | |||
744 | pr_info("Trying %d/%s\n", | ||
745 | phydev->speed, | ||
746 | DUPLEX_FULL == | ||
747 | phydev->duplex ? | ||
748 | "FULL" : "HALF"); | ||
749 | } | ||
750 | |||
751 | needs_aneg = 1; | ||
752 | } | ||
753 | break; | ||
754 | case PHY_NOLINK: | ||
755 | err = phy_read_status(phydev); | ||
756 | |||
757 | if (err) | ||
758 | break; | ||
759 | |||
760 | if (phydev->link) { | ||
761 | phydev->state = PHY_RUNNING; | ||
762 | netif_carrier_on(phydev->attached_dev); | ||
763 | phydev->adjust_link(phydev->attached_dev); | ||
764 | } | ||
765 | break; | ||
766 | case PHY_FORCING: | ||
767 | err = phy_read_status(phydev); | ||
768 | |||
769 | if (err) | ||
770 | break; | ||
771 | |||
772 | if (phydev->link) { | ||
773 | phydev->state = PHY_RUNNING; | ||
774 | netif_carrier_on(phydev->attached_dev); | ||
775 | } else { | ||
776 | if (0 == phydev->link_timeout--) { | ||
777 | phy_force_reduction(phydev); | ||
778 | needs_aneg = 1; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | phydev->adjust_link(phydev->attached_dev); | ||
783 | break; | ||
784 | case PHY_RUNNING: | ||
785 | /* Only register a CHANGE if we are | ||
786 | * polling */ | ||
787 | if (PHY_POLL == phydev->irq) | ||
788 | phydev->state = PHY_CHANGELINK; | ||
789 | break; | ||
790 | case PHY_CHANGELINK: | ||
791 | err = phy_read_status(phydev); | ||
792 | |||
793 | if (err) | ||
794 | break; | ||
795 | |||
796 | if (phydev->link) { | ||
797 | phydev->state = PHY_RUNNING; | ||
798 | netif_carrier_on(phydev->attached_dev); | ||
799 | } else { | ||
800 | phydev->state = PHY_NOLINK; | ||
801 | netif_carrier_off(phydev->attached_dev); | ||
802 | } | ||
803 | |||
804 | phydev->adjust_link(phydev->attached_dev); | ||
805 | |||
806 | if (PHY_POLL != phydev->irq) | ||
807 | err = phy_config_interrupt(phydev, | ||
808 | PHY_INTERRUPT_ENABLED); | ||
809 | break; | ||
810 | case PHY_HALTED: | ||
811 | if (phydev->link) { | ||
812 | phydev->link = 0; | ||
813 | netif_carrier_off(phydev->attached_dev); | ||
814 | phydev->adjust_link(phydev->attached_dev); | ||
815 | } | ||
816 | break; | ||
817 | case PHY_RESUMING: | ||
818 | |||
819 | err = phy_clear_interrupt(phydev); | ||
820 | |||
821 | if (err) | ||
822 | break; | ||
823 | |||
824 | err = phy_config_interrupt(phydev, | ||
825 | PHY_INTERRUPT_ENABLED); | ||
826 | |||
827 | if (err) | ||
828 | break; | ||
829 | |||
830 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
831 | err = phy_aneg_done(phydev); | ||
832 | if (err < 0) | ||
833 | break; | ||
834 | |||
835 | /* err > 0 if AN is done. | ||
836 | * Otherwise, it's 0, and we're | ||
837 | * still waiting for AN */ | ||
838 | if (err > 0) { | ||
839 | phydev->state = PHY_RUNNING; | ||
840 | } else { | ||
841 | phydev->state = PHY_AN; | ||
842 | phydev->link_timeout = PHY_AN_TIMEOUT; | ||
843 | } | ||
844 | } else | ||
845 | phydev->state = PHY_RUNNING; | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | spin_unlock(&phydev->lock); | ||
850 | |||
851 | if (needs_aneg) | ||
852 | err = phy_start_aneg(phydev); | ||
853 | |||
854 | if (err < 0) | ||
855 | phy_error(phydev); | ||
856 | |||
857 | mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); | ||
858 | } | ||
859 | |||
860 | #endif /* CONFIG_PHYCONTROL */ | ||
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c new file mode 100644 index 000000000000..f0595af4c837 --- /dev/null +++ b/drivers/net/phy/phy_device.c | |||
@@ -0,0 +1,682 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/phy_device.c | ||
3 | * | ||
4 | * Framework for finding and configuring PHYs. | ||
5 | * Also contains generic PHY driver | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * | ||
9 | * Copyright (c) 2004 Freescale Semiconductor, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/phy.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | /* get_phy_device | ||
43 | * | ||
44 | * description: Reads the ID registers of the PHY at addr on the | ||
45 | * bus, then allocates and returns the phy_device to | ||
46 | * represent it. | ||
47 | */ | ||
48 | struct phy_device * get_phy_device(struct mii_bus *bus, int addr) | ||
49 | { | ||
50 | int phy_reg; | ||
51 | u32 phy_id; | ||
52 | struct phy_device *dev = NULL; | ||
53 | |||
54 | /* Grab the bits from PHYIR1, and put them | ||
55 | * in the upper half */ | ||
56 | phy_reg = bus->read(bus, addr, MII_PHYSID1); | ||
57 | |||
58 | if (phy_reg < 0) | ||
59 | return ERR_PTR(phy_reg); | ||
60 | |||
61 | phy_id = (phy_reg & 0xffff) << 16; | ||
62 | |||
63 | /* Grab the bits from PHYIR2, and put them in the lower half */ | ||
64 | phy_reg = bus->read(bus, addr, MII_PHYSID2); | ||
65 | |||
66 | if (phy_reg < 0) | ||
67 | return ERR_PTR(phy_reg); | ||
68 | |||
69 | phy_id |= (phy_reg & 0xffff); | ||
70 | |||
71 | /* If the phy_id is all Fs, there is no device there */ | ||
72 | if (0xffffffff == phy_id) | ||
73 | return NULL; | ||
74 | |||
75 | /* Otherwise, we allocate the device, and initialize the | ||
76 | * default values */ | ||
77 | dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); | ||
78 | |||
79 | if (NULL == dev) | ||
80 | return ERR_PTR(-ENOMEM); | ||
81 | |||
82 | dev->speed = 0; | ||
83 | dev->duplex = -1; | ||
84 | dev->pause = dev->asym_pause = 0; | ||
85 | dev->link = 1; | ||
86 | |||
87 | dev->autoneg = AUTONEG_ENABLE; | ||
88 | |||
89 | dev->addr = addr; | ||
90 | dev->phy_id = phy_id; | ||
91 | dev->bus = bus; | ||
92 | |||
93 | dev->state = PHY_DOWN; | ||
94 | |||
95 | spin_lock_init(&dev->lock); | ||
96 | |||
97 | return dev; | ||
98 | } | ||
99 | |||
100 | /* phy_prepare_link: | ||
101 | * | ||
102 | * description: Tells the PHY infrastructure to handle the | ||
103 | * gory details on monitoring link status (whether through | ||
104 | * polling or an interrupt), and to call back to the | ||
105 | * connected device driver when the link status changes. | ||
106 | * If you want to monitor your own link state, don't call | ||
107 | * this function */ | ||
108 | void phy_prepare_link(struct phy_device *phydev, | ||
109 | void (*handler)(struct net_device *)) | ||
110 | { | ||
111 | phydev->adjust_link = handler; | ||
112 | } | ||
113 | |||
114 | #ifdef CONFIG_PHYCONTROL | ||
115 | /* phy_connect: | ||
116 | * | ||
117 | * description: Convenience function for connecting ethernet | ||
118 | * devices to PHY devices. The default behavior is for | ||
119 | * the PHY infrastructure to handle everything, and only notify | ||
120 | * the connected driver when the link status changes. If you | ||
121 | * don't want, or can't use the provided functionality, you may | ||
122 | * choose to call only the subset of functions which provide | ||
123 | * the desired functionality. | ||
124 | */ | ||
125 | struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | ||
126 | void (*handler)(struct net_device *), u32 flags) | ||
127 | { | ||
128 | struct phy_device *phydev; | ||
129 | |||
130 | phydev = phy_attach(dev, phy_id, flags); | ||
131 | |||
132 | if (IS_ERR(phydev)) | ||
133 | return phydev; | ||
134 | |||
135 | phy_prepare_link(phydev, handler); | ||
136 | |||
137 | phy_start_machine(phydev, NULL); | ||
138 | |||
139 | if (phydev->irq > 0) | ||
140 | phy_start_interrupts(phydev); | ||
141 | |||
142 | return phydev; | ||
143 | } | ||
144 | EXPORT_SYMBOL(phy_connect); | ||
145 | |||
146 | void phy_disconnect(struct phy_device *phydev) | ||
147 | { | ||
148 | if (phydev->irq > 0) | ||
149 | phy_stop_interrupts(phydev); | ||
150 | |||
151 | phy_stop_machine(phydev); | ||
152 | |||
153 | phydev->adjust_link = NULL; | ||
154 | |||
155 | phy_detach(phydev); | ||
156 | } | ||
157 | EXPORT_SYMBOL(phy_disconnect); | ||
158 | |||
159 | #endif /* CONFIG_PHYCONTROL */ | ||
160 | |||
161 | /* phy_attach: | ||
162 | * | ||
163 | * description: Called by drivers to attach to a particular PHY | ||
164 | * device. The phy_device is found, and properly hooked up | ||
165 | * to the phy_driver. If no driver is attached, then the | ||
166 | * genphy_driver is used. The phy_device is given a ptr to | ||
167 | * the attaching device, and given a callback for link status | ||
168 | * change. The phy_device is returned to the attaching | ||
169 | * driver. | ||
170 | */ | ||
171 | static int phy_compare_id(struct device *dev, void *data) | ||
172 | { | ||
173 | return strcmp((char *)data, dev->bus_id) ? 0 : 1; | ||
174 | } | ||
175 | |||
176 | struct phy_device *phy_attach(struct net_device *dev, | ||
177 | const char *phy_id, u32 flags) | ||
178 | { | ||
179 | struct bus_type *bus = &mdio_bus_type; | ||
180 | struct phy_device *phydev; | ||
181 | struct device *d; | ||
182 | |||
183 | /* Search the list of PHY devices on the mdio bus for the | ||
184 | * PHY with the requested name */ | ||
185 | d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); | ||
186 | |||
187 | if (d) { | ||
188 | phydev = to_phy_device(d); | ||
189 | } else { | ||
190 | printk(KERN_ERR "%s not found\n", phy_id); | ||
191 | return ERR_PTR(-ENODEV); | ||
192 | } | ||
193 | |||
194 | /* Assume that if there is no driver, that it doesn't | ||
195 | * exist, and we should use the genphy driver. */ | ||
196 | if (NULL == d->driver) { | ||
197 | int err; | ||
198 | down_write(&d->bus->subsys.rwsem); | ||
199 | d->driver = &genphy_driver.driver; | ||
200 | |||
201 | err = d->driver->probe(d); | ||
202 | |||
203 | if (err < 0) | ||
204 | return ERR_PTR(err); | ||
205 | |||
206 | device_bind_driver(d); | ||
207 | up_write(&d->bus->subsys.rwsem); | ||
208 | } | ||
209 | |||
210 | if (phydev->attached_dev) { | ||
211 | printk(KERN_ERR "%s: %s already attached\n", | ||
212 | dev->name, phy_id); | ||
213 | return ERR_PTR(-EBUSY); | ||
214 | } | ||
215 | |||
216 | phydev->attached_dev = dev; | ||
217 | |||
218 | phydev->dev_flags = flags; | ||
219 | |||
220 | return phydev; | ||
221 | } | ||
222 | EXPORT_SYMBOL(phy_attach); | ||
223 | |||
224 | void phy_detach(struct phy_device *phydev) | ||
225 | { | ||
226 | phydev->attached_dev = NULL; | ||
227 | |||
228 | /* If the device had no specific driver before (i.e. - it | ||
229 | * was using the generic driver), we unbind the device | ||
230 | * from the generic driver so that there's a chance a | ||
231 | * real driver could be loaded */ | ||
232 | if (phydev->dev.driver == &genphy_driver.driver) { | ||
233 | down_write(&phydev->dev.bus->subsys.rwsem); | ||
234 | device_release_driver(&phydev->dev); | ||
235 | up_write(&phydev->dev.bus->subsys.rwsem); | ||
236 | } | ||
237 | } | ||
238 | EXPORT_SYMBOL(phy_detach); | ||
239 | |||
240 | |||
241 | /* Generic PHY support and helper functions */ | ||
242 | |||
243 | /* genphy_config_advert | ||
244 | * | ||
245 | * description: Writes MII_ADVERTISE with the appropriate values, | ||
246 | * after sanitizing the values to make sure we only advertise | ||
247 | * what is supported | ||
248 | */ | ||
249 | int genphy_config_advert(struct phy_device *phydev) | ||
250 | { | ||
251 | u32 advertise; | ||
252 | int adv; | ||
253 | int err; | ||
254 | |||
255 | /* Only allow advertising what | ||
256 | * this PHY supports */ | ||
257 | phydev->advertising &= phydev->supported; | ||
258 | advertise = phydev->advertising; | ||
259 | |||
260 | /* Setup standard advertisement */ | ||
261 | adv = phy_read(phydev, MII_ADVERTISE); | ||
262 | |||
263 | if (adv < 0) | ||
264 | return adv; | ||
265 | |||
266 | adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | | ||
267 | ADVERTISE_PAUSE_ASYM); | ||
268 | if (advertise & ADVERTISED_10baseT_Half) | ||
269 | adv |= ADVERTISE_10HALF; | ||
270 | if (advertise & ADVERTISED_10baseT_Full) | ||
271 | adv |= ADVERTISE_10FULL; | ||
272 | if (advertise & ADVERTISED_100baseT_Half) | ||
273 | adv |= ADVERTISE_100HALF; | ||
274 | if (advertise & ADVERTISED_100baseT_Full) | ||
275 | adv |= ADVERTISE_100FULL; | ||
276 | if (advertise & ADVERTISED_Pause) | ||
277 | adv |= ADVERTISE_PAUSE_CAP; | ||
278 | if (advertise & ADVERTISED_Asym_Pause) | ||
279 | adv |= ADVERTISE_PAUSE_ASYM; | ||
280 | |||
281 | err = phy_write(phydev, MII_ADVERTISE, adv); | ||
282 | |||
283 | if (err < 0) | ||
284 | return err; | ||
285 | |||
286 | /* Configure gigabit if it's supported */ | ||
287 | if (phydev->supported & (SUPPORTED_1000baseT_Half | | ||
288 | SUPPORTED_1000baseT_Full)) { | ||
289 | adv = phy_read(phydev, MII_CTRL1000); | ||
290 | |||
291 | if (adv < 0) | ||
292 | return adv; | ||
293 | |||
294 | adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); | ||
295 | if (advertise & SUPPORTED_1000baseT_Half) | ||
296 | adv |= ADVERTISE_1000HALF; | ||
297 | if (advertise & SUPPORTED_1000baseT_Full) | ||
298 | adv |= ADVERTISE_1000FULL; | ||
299 | err = phy_write(phydev, MII_CTRL1000, adv); | ||
300 | |||
301 | if (err < 0) | ||
302 | return err; | ||
303 | } | ||
304 | |||
305 | return adv; | ||
306 | } | ||
307 | EXPORT_SYMBOL(genphy_config_advert); | ||
308 | |||
309 | /* genphy_setup_forced | ||
310 | * | ||
311 | * description: Configures MII_BMCR to force speed/duplex | ||
312 | * to the values in phydev. Assumes that the values are valid. | ||
313 | * Please see phy_sanitize_settings() */ | ||
314 | int genphy_setup_forced(struct phy_device *phydev) | ||
315 | { | ||
316 | int ctl = BMCR_RESET; | ||
317 | |||
318 | phydev->pause = phydev->asym_pause = 0; | ||
319 | |||
320 | if (SPEED_1000 == phydev->speed) | ||
321 | ctl |= BMCR_SPEED1000; | ||
322 | else if (SPEED_100 == phydev->speed) | ||
323 | ctl |= BMCR_SPEED100; | ||
324 | |||
325 | if (DUPLEX_FULL == phydev->duplex) | ||
326 | ctl |= BMCR_FULLDPLX; | ||
327 | |||
328 | ctl = phy_write(phydev, MII_BMCR, ctl); | ||
329 | |||
330 | if (ctl < 0) | ||
331 | return ctl; | ||
332 | |||
333 | /* We just reset the device, so we'd better configure any | ||
334 | * settings the PHY requires to operate */ | ||
335 | if (phydev->drv->config_init) | ||
336 | ctl = phydev->drv->config_init(phydev); | ||
337 | |||
338 | return ctl; | ||
339 | } | ||
340 | |||
341 | |||
342 | /* Enable and Restart Autonegotiation */ | ||
343 | int genphy_restart_aneg(struct phy_device *phydev) | ||
344 | { | ||
345 | int ctl; | ||
346 | |||
347 | ctl = phy_read(phydev, MII_BMCR); | ||
348 | |||
349 | if (ctl < 0) | ||
350 | return ctl; | ||
351 | |||
352 | ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
353 | |||
354 | /* Don't isolate the PHY if we're negotiating */ | ||
355 | ctl &= ~(BMCR_ISOLATE); | ||
356 | |||
357 | ctl = phy_write(phydev, MII_BMCR, ctl); | ||
358 | |||
359 | return ctl; | ||
360 | } | ||
361 | |||
362 | |||
363 | /* genphy_config_aneg | ||
364 | * | ||
365 | * description: If auto-negotiation is enabled, we configure the | ||
366 | * advertising, and then restart auto-negotiation. If it is not | ||
367 | * enabled, then we write the BMCR | ||
368 | */ | ||
369 | int genphy_config_aneg(struct phy_device *phydev) | ||
370 | { | ||
371 | int err = 0; | ||
372 | |||
373 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
374 | err = genphy_config_advert(phydev); | ||
375 | |||
376 | if (err < 0) | ||
377 | return err; | ||
378 | |||
379 | err = genphy_restart_aneg(phydev); | ||
380 | } else | ||
381 | err = genphy_setup_forced(phydev); | ||
382 | |||
383 | return err; | ||
384 | } | ||
385 | EXPORT_SYMBOL(genphy_config_aneg); | ||
386 | |||
387 | /* genphy_update_link | ||
388 | * | ||
389 | * description: Update the value in phydev->link to reflect the | ||
390 | * current link value. In order to do this, we need to read | ||
391 | * the status register twice, keeping the second value | ||
392 | */ | ||
393 | int genphy_update_link(struct phy_device *phydev) | ||
394 | { | ||
395 | int status; | ||
396 | |||
397 | /* Do a fake read */ | ||
398 | status = phy_read(phydev, MII_BMSR); | ||
399 | |||
400 | if (status < 0) | ||
401 | return status; | ||
402 | |||
403 | /* Read link and autonegotiation status */ | ||
404 | status = phy_read(phydev, MII_BMSR); | ||
405 | |||
406 | if (status < 0) | ||
407 | return status; | ||
408 | |||
409 | if ((status & BMSR_LSTATUS) == 0) | ||
410 | phydev->link = 0; | ||
411 | else | ||
412 | phydev->link = 1; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | /* genphy_read_status | ||
418 | * | ||
419 | * description: Check the link, then figure out the current state | ||
420 | * by comparing what we advertise with what the link partner | ||
421 | * advertises. Start by checking the gigabit possibilities, | ||
422 | * then move on to 10/100. | ||
423 | */ | ||
424 | int genphy_read_status(struct phy_device *phydev) | ||
425 | { | ||
426 | int adv; | ||
427 | int err; | ||
428 | int lpa; | ||
429 | int lpagb = 0; | ||
430 | |||
431 | /* Update the link, but return if there | ||
432 | * was an error */ | ||
433 | err = genphy_update_link(phydev); | ||
434 | if (err) | ||
435 | return err; | ||
436 | |||
437 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
438 | if (phydev->supported & (SUPPORTED_1000baseT_Half | ||
439 | | SUPPORTED_1000baseT_Full)) { | ||
440 | lpagb = phy_read(phydev, MII_STAT1000); | ||
441 | |||
442 | if (lpagb < 0) | ||
443 | return lpagb; | ||
444 | |||
445 | adv = phy_read(phydev, MII_CTRL1000); | ||
446 | |||
447 | if (adv < 0) | ||
448 | return adv; | ||
449 | |||
450 | lpagb &= adv << 2; | ||
451 | } | ||
452 | |||
453 | lpa = phy_read(phydev, MII_LPA); | ||
454 | |||
455 | if (lpa < 0) | ||
456 | return lpa; | ||
457 | |||
458 | adv = phy_read(phydev, MII_ADVERTISE); | ||
459 | |||
460 | if (adv < 0) | ||
461 | return adv; | ||
462 | |||
463 | lpa &= adv; | ||
464 | |||
465 | phydev->speed = SPEED_10; | ||
466 | phydev->duplex = DUPLEX_HALF; | ||
467 | phydev->pause = phydev->asym_pause = 0; | ||
468 | |||
469 | if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { | ||
470 | phydev->speed = SPEED_1000; | ||
471 | |||
472 | if (lpagb & LPA_1000FULL) | ||
473 | phydev->duplex = DUPLEX_FULL; | ||
474 | } else if (lpa & (LPA_100FULL | LPA_100HALF)) { | ||
475 | phydev->speed = SPEED_100; | ||
476 | |||
477 | if (lpa & LPA_100FULL) | ||
478 | phydev->duplex = DUPLEX_FULL; | ||
479 | } else | ||
480 | if (lpa & LPA_10FULL) | ||
481 | phydev->duplex = DUPLEX_FULL; | ||
482 | |||
483 | if (phydev->duplex == DUPLEX_FULL){ | ||
484 | phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; | ||
485 | phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; | ||
486 | } | ||
487 | } else { | ||
488 | int bmcr = phy_read(phydev, MII_BMCR); | ||
489 | if (bmcr < 0) | ||
490 | return bmcr; | ||
491 | |||
492 | if (bmcr & BMCR_FULLDPLX) | ||
493 | phydev->duplex = DUPLEX_FULL; | ||
494 | else | ||
495 | phydev->duplex = DUPLEX_HALF; | ||
496 | |||
497 | if (bmcr & BMCR_SPEED1000) | ||
498 | phydev->speed = SPEED_1000; | ||
499 | else if (bmcr & BMCR_SPEED100) | ||
500 | phydev->speed = SPEED_100; | ||
501 | else | ||
502 | phydev->speed = SPEED_10; | ||
503 | |||
504 | phydev->pause = phydev->asym_pause = 0; | ||
505 | } | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | EXPORT_SYMBOL(genphy_read_status); | ||
510 | |||
511 | static int genphy_config_init(struct phy_device *phydev) | ||
512 | { | ||
513 | u32 val; | ||
514 | u32 features; | ||
515 | |||
516 | /* For now, I'll claim that the generic driver supports | ||
517 | * all possible port types */ | ||
518 | features = (SUPPORTED_TP | SUPPORTED_MII | ||
519 | | SUPPORTED_AUI | SUPPORTED_FIBRE | | ||
520 | SUPPORTED_BNC); | ||
521 | |||
522 | /* Do we support autonegotiation? */ | ||
523 | val = phy_read(phydev, MII_BMSR); | ||
524 | |||
525 | if (val < 0) | ||
526 | return val; | ||
527 | |||
528 | if (val & BMSR_ANEGCAPABLE) | ||
529 | features |= SUPPORTED_Autoneg; | ||
530 | |||
531 | if (val & BMSR_100FULL) | ||
532 | features |= SUPPORTED_100baseT_Full; | ||
533 | if (val & BMSR_100HALF) | ||
534 | features |= SUPPORTED_100baseT_Half; | ||
535 | if (val & BMSR_10FULL) | ||
536 | features |= SUPPORTED_10baseT_Full; | ||
537 | if (val & BMSR_10HALF) | ||
538 | features |= SUPPORTED_10baseT_Half; | ||
539 | |||
540 | if (val & BMSR_ESTATEN) { | ||
541 | val = phy_read(phydev, MII_ESTATUS); | ||
542 | |||
543 | if (val < 0) | ||
544 | return val; | ||
545 | |||
546 | if (val & ESTATUS_1000_TFULL) | ||
547 | features |= SUPPORTED_1000baseT_Full; | ||
548 | if (val & ESTATUS_1000_THALF) | ||
549 | features |= SUPPORTED_1000baseT_Half; | ||
550 | } | ||
551 | |||
552 | phydev->supported = features; | ||
553 | phydev->advertising = features; | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | |||
559 | /* phy_probe | ||
560 | * | ||
561 | * description: Take care of setting up the phy_device structure, | ||
562 | * set the state to READY (the driver's init function should | ||
563 | * set it to STARTING if needed). | ||
564 | */ | ||
565 | static int phy_probe(struct device *dev) | ||
566 | { | ||
567 | struct phy_device *phydev; | ||
568 | struct phy_driver *phydrv; | ||
569 | struct device_driver *drv; | ||
570 | int err = 0; | ||
571 | |||
572 | phydev = to_phy_device(dev); | ||
573 | |||
574 | /* Make sure the driver is held. | ||
575 | * XXX -- Is this correct? */ | ||
576 | drv = get_driver(phydev->dev.driver); | ||
577 | phydrv = to_phy_driver(drv); | ||
578 | phydev->drv = phydrv; | ||
579 | |||
580 | /* Disable the interrupt if the PHY doesn't support it */ | ||
581 | if (!(phydrv->flags & PHY_HAS_INTERRUPT)) | ||
582 | phydev->irq = PHY_POLL; | ||
583 | |||
584 | spin_lock(&phydev->lock); | ||
585 | |||
586 | /* Start out supporting everything. Eventually, | ||
587 | * a controller will attach, and may modify one | ||
588 | * or both of these values */ | ||
589 | phydev->supported = phydrv->features; | ||
590 | phydev->advertising = phydrv->features; | ||
591 | |||
592 | /* Set the state to READY by default */ | ||
593 | phydev->state = PHY_READY; | ||
594 | |||
595 | if (phydev->drv->probe) | ||
596 | err = phydev->drv->probe(phydev); | ||
597 | |||
598 | spin_unlock(&phydev->lock); | ||
599 | |||
600 | if (err < 0) | ||
601 | return err; | ||
602 | |||
603 | if (phydev->drv->config_init) | ||
604 | err = phydev->drv->config_init(phydev); | ||
605 | |||
606 | return err; | ||
607 | } | ||
608 | |||
609 | static int phy_remove(struct device *dev) | ||
610 | { | ||
611 | struct phy_device *phydev; | ||
612 | |||
613 | phydev = to_phy_device(dev); | ||
614 | |||
615 | spin_lock(&phydev->lock); | ||
616 | phydev->state = PHY_DOWN; | ||
617 | spin_unlock(&phydev->lock); | ||
618 | |||
619 | if (phydev->drv->remove) | ||
620 | phydev->drv->remove(phydev); | ||
621 | |||
622 | put_driver(dev->driver); | ||
623 | phydev->drv = NULL; | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | int phy_driver_register(struct phy_driver *new_driver) | ||
629 | { | ||
630 | int retval; | ||
631 | |||
632 | memset(&new_driver->driver, 0, sizeof(new_driver->driver)); | ||
633 | new_driver->driver.name = new_driver->name; | ||
634 | new_driver->driver.bus = &mdio_bus_type; | ||
635 | new_driver->driver.probe = phy_probe; | ||
636 | new_driver->driver.remove = phy_remove; | ||
637 | |||
638 | retval = driver_register(&new_driver->driver); | ||
639 | |||
640 | if (retval) { | ||
641 | printk(KERN_ERR "%s: Error %d in registering driver\n", | ||
642 | new_driver->name, retval); | ||
643 | |||
644 | return retval; | ||
645 | } | ||
646 | |||
647 | pr_info("%s: Registered new driver\n", new_driver->name); | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | EXPORT_SYMBOL(phy_driver_register); | ||
652 | |||
653 | void phy_driver_unregister(struct phy_driver *drv) | ||
654 | { | ||
655 | driver_unregister(&drv->driver); | ||
656 | } | ||
657 | EXPORT_SYMBOL(phy_driver_unregister); | ||
658 | |||
659 | static struct phy_driver genphy_driver = { | ||
660 | .phy_id = 0xffffffff, | ||
661 | .phy_id_mask = 0xffffffff, | ||
662 | .name = "Generic PHY", | ||
663 | .config_init = genphy_config_init, | ||
664 | .features = 0, | ||
665 | .config_aneg = genphy_config_aneg, | ||
666 | .read_status = genphy_read_status, | ||
667 | .driver = {.owner = THIS_MODULE, }, | ||
668 | }; | ||
669 | |||
670 | static int __init genphy_init(void) | ||
671 | { | ||
672 | return phy_driver_register(&genphy_driver); | ||
673 | |||
674 | } | ||
675 | |||
676 | static void __exit genphy_exit(void) | ||
677 | { | ||
678 | phy_driver_unregister(&genphy_driver); | ||
679 | } | ||
680 | |||
681 | module_init(genphy_init); | ||
682 | module_exit(genphy_exit); | ||
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c new file mode 100644 index 000000000000..d461ba457631 --- /dev/null +++ b/drivers/net/phy/qsemi.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * drivers/net/phy/qsemi.c | ||
3 | * | ||
4 | * Driver for Quality Semiconductor PHYs | ||
5 | * | ||
6 | * Author: Andy Fleming | ||
7 | * | ||
8 | * Copyright (c) 2004 Freescale Semiconductor, 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/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/version.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/phy.h> | ||
36 | |||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | /* ------------------------------------------------------------------------- */ | ||
42 | /* The Quality Semiconductor QS6612 is used on the RPX CLLF */ | ||
43 | |||
44 | /* register definitions */ | ||
45 | |||
46 | #define MII_QS6612_MCR 17 /* Mode Control Register */ | ||
47 | #define MII_QS6612_FTR 27 /* Factory Test Register */ | ||
48 | #define MII_QS6612_MCO 28 /* Misc. Control Register */ | ||
49 | #define MII_QS6612_ISR 29 /* Interrupt Source Register */ | ||
50 | #define MII_QS6612_IMR 30 /* Interrupt Mask Register */ | ||
51 | #define MII_QS6612_IMR_INIT 0x003a | ||
52 | #define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ | ||
53 | |||
54 | #define QS6612_PCR_AN_COMPLETE 0x1000 | ||
55 | #define QS6612_PCR_RLBEN 0x0200 | ||
56 | #define QS6612_PCR_DCREN 0x0100 | ||
57 | #define QS6612_PCR_4B5BEN 0x0040 | ||
58 | #define QS6612_PCR_TX_ISOLATE 0x0020 | ||
59 | #define QS6612_PCR_MLT3_DIS 0x0002 | ||
60 | #define QS6612_PCR_SCRM_DESCRM 0x0001 | ||
61 | |||
62 | MODULE_DESCRIPTION("Quality Semiconductor PHY driver"); | ||
63 | MODULE_AUTHOR("Andy Fleming"); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | /* Returns 0, unless there's a write error */ | ||
67 | static int qs6612_config_init(struct phy_device *phydev) | ||
68 | { | ||
69 | /* The PHY powers up isolated on the RPX, | ||
70 | * so send a command to allow operation. | ||
71 | * XXX - My docs indicate this should be 0x0940 | ||
72 | * ...or something. The current value sets three | ||
73 | * reserved bits, bit 11, which specifies it should be | ||
74 | * set to one, bit 10, which specifies it should be set | ||
75 | * to 0, and bit 7, which doesn't specify. However, my | ||
76 | * docs are preliminary, and I will leave it like this | ||
77 | * until someone more knowledgable corrects me or it. | ||
78 | * -- Andy Fleming | ||
79 | */ | ||
80 | return phy_write(phydev, MII_QS6612_PCR, 0x0dc0); | ||
81 | } | ||
82 | |||
83 | static int qs6612_ack_interrupt(struct phy_device *phydev) | ||
84 | { | ||
85 | int err; | ||
86 | |||
87 | err = phy_read(phydev, MII_QS6612_ISR); | ||
88 | |||
89 | if (err < 0) | ||
90 | return err; | ||
91 | |||
92 | err = phy_read(phydev, MII_BMSR); | ||
93 | |||
94 | if (err < 0) | ||
95 | return err; | ||
96 | |||
97 | err = phy_read(phydev, MII_EXPANSION); | ||
98 | |||
99 | if (err < 0) | ||
100 | return err; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int qs6612_config_intr(struct phy_device *phydev) | ||
106 | { | ||
107 | int err; | ||
108 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | ||
109 | err = phy_write(phydev, MII_QS6612_IMR, | ||
110 | MII_QS6612_IMR_INIT); | ||
111 | else | ||
112 | err = phy_write(phydev, MII_QS6612_IMR, 0); | ||
113 | |||
114 | return err; | ||
115 | |||
116 | } | ||
117 | |||
118 | static struct phy_driver qs6612_driver = { | ||
119 | .phy_id = 0x00181440, | ||
120 | .name = "QS6612", | ||
121 | .phy_id_mask = 0xfffffff0, | ||
122 | .features = PHY_BASIC_FEATURES, | ||
123 | .flags = PHY_HAS_INTERRUPT, | ||
124 | .config_init = qs6612_config_init, | ||
125 | .config_aneg = genphy_config_aneg, | ||
126 | .read_status = genphy_read_status, | ||
127 | .ack_interrupt = qs6612_ack_interrupt, | ||
128 | .config_intr = qs6612_config_intr, | ||
129 | .driver = { .owner = THIS_MODULE,}, | ||
130 | }; | ||
131 | |||
132 | static int __init qs6612_init(void) | ||
133 | { | ||
134 | return phy_driver_register(&qs6612_driver); | ||
135 | } | ||
136 | |||
137 | static void __exit qs6612_exit(void) | ||
138 | { | ||
139 | phy_driver_unregister(&qs6612_driver); | ||
140 | } | ||
141 | |||
142 | module_init(qs6612_init); | ||
143 | module_exit(qs6612_exit); | ||