aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Tabi <timur@codeaurora.org>2017-01-27 17:43:48 -0500
committerDavid S. Miller <davem@davemloft.net>2017-01-29 19:07:02 -0500
commitfd0e97b806f0331df95f5fc58cdd488d169efb7f (patch)
tree0dc31f4a8d67dbc675a99c5e7def5aa10f058ab2
parente7e7454b40d290f6efb63c792c56c416922dcef8 (diff)
net: qcom/emac: add an error interrupt handler for the sgmii
The SGMII (internal PHY) can report decode errors via an interrupt. It can also report autonegotiation status changes, but we don't need to track those. The SGMII can recover automatically from most decode errors, so we only reset the interface if we get multiple consecutive errors. It's possible for bogus decode errors to be reported while the link is being brought up. The interrupt is registered when the interface is opened, and it's enabled after the link is up. Signed-off-by: Timur Tabi <timur@codeaurora.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-mac.c8
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.c126
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac-sgmii.h16
-rw-r--r--drivers/net/ethernet/qualcomm/emac/emac.c10
4 files changed, 153 insertions, 7 deletions
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
index 33d7ff1f40e0..b991219862b1 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c
@@ -951,12 +951,16 @@ static void emac_mac_rx_descs_refill(struct emac_adapter *adpt,
951static void emac_adjust_link(struct net_device *netdev) 951static void emac_adjust_link(struct net_device *netdev)
952{ 952{
953 struct emac_adapter *adpt = netdev_priv(netdev); 953 struct emac_adapter *adpt = netdev_priv(netdev);
954 struct emac_sgmii *sgmii = &adpt->phy;
954 struct phy_device *phydev = netdev->phydev; 955 struct phy_device *phydev = netdev->phydev;
955 956
956 if (phydev->link) 957 if (phydev->link) {
957 emac_mac_start(adpt); 958 emac_mac_start(adpt);
958 else 959 sgmii->link_up(adpt);
960 } else {
961 sgmii->link_down(adpt);
959 emac_mac_stop(adpt); 962 emac_mac_stop(adpt);
963 }
960 964
961 phy_print_status(phydev); 965 phy_print_status(phydev);
962} 966}
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
index b5269c4dd4ee..040b28977ee7 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c
@@ -25,7 +25,9 @@
25#define EMAC_SGMII_PHY_SPEED_CFG1 0x0074 25#define EMAC_SGMII_PHY_SPEED_CFG1 0x0074
26#define EMAC_SGMII_PHY_IRQ_CMD 0x00ac 26#define EMAC_SGMII_PHY_IRQ_CMD 0x00ac
27#define EMAC_SGMII_PHY_INTERRUPT_CLEAR 0x00b0 27#define EMAC_SGMII_PHY_INTERRUPT_CLEAR 0x00b0
28#define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4
28#define EMAC_SGMII_PHY_INTERRUPT_STATUS 0x00b8 29#define EMAC_SGMII_PHY_INTERRUPT_STATUS 0x00b8
30#define EMAC_SGMII_PHY_RX_CHK_STATUS 0x00d4
29 31
30#define FORCE_AN_TX_CFG BIT(5) 32#define FORCE_AN_TX_CFG BIT(5)
31#define FORCE_AN_RX_CFG BIT(4) 33#define FORCE_AN_RX_CFG BIT(4)
@@ -36,6 +38,8 @@
36#define SPDMODE_100 BIT(0) 38#define SPDMODE_100 BIT(0)
37#define SPDMODE_10 0 39#define SPDMODE_10 0
38 40
41#define CDR_ALIGN_DET BIT(6)
42
39#define IRQ_GLOBAL_CLEAR BIT(0) 43#define IRQ_GLOBAL_CLEAR BIT(0)
40 44
41#define DECODE_CODE_ERR BIT(7) 45#define DECODE_CODE_ERR BIT(7)
@@ -44,6 +48,7 @@
44#define SGMII_PHY_IRQ_CLR_WAIT_TIME 10 48#define SGMII_PHY_IRQ_CLR_WAIT_TIME 10
45 49
46#define SGMII_PHY_INTERRUPT_ERR (DECODE_CODE_ERR | DECODE_DISP_ERR) 50#define SGMII_PHY_INTERRUPT_ERR (DECODE_CODE_ERR | DECODE_DISP_ERR)
51#define SGMII_ISR_MASK (SGMII_PHY_INTERRUPT_ERR)
47 52
48#define SERDES_START_WAIT_TIMES 100 53#define SERDES_START_WAIT_TIMES 100
49 54
@@ -96,6 +101,51 @@ static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits)
96 return 0; 101 return 0;
97} 102}
98 103
104/* The number of decode errors that triggers a reset */
105#define DECODE_ERROR_LIMIT 2
106
107static irqreturn_t emac_sgmii_interrupt(int irq, void *data)
108{
109 struct emac_adapter *adpt = data;
110 struct emac_sgmii *phy = &adpt->phy;
111 u32 status;
112
113 status = readl(phy->base + EMAC_SGMII_PHY_INTERRUPT_STATUS);
114 status &= SGMII_ISR_MASK;
115 if (!status)
116 return IRQ_HANDLED;
117
118 /* If we get a decoding error and CDR is not locked, then try
119 * resetting the internal PHY. The internal PHY uses an embedded
120 * clock with Clock and Data Recovery (CDR) to recover the
121 * clock and data.
122 */
123 if (status & SGMII_PHY_INTERRUPT_ERR) {
124 int count;
125
126 /* The SGMII is capable of recovering from some decode
127 * errors automatically. However, if we get multiple
128 * decode errors in a row, then assume that something
129 * is wrong and reset the interface.
130 */
131 count = atomic_inc_return(&phy->decode_error_count);
132 if (count == DECODE_ERROR_LIMIT) {
133 schedule_work(&adpt->work_thread);
134 atomic_set(&phy->decode_error_count, 0);
135 }
136 } else {
137 /* We only care about consecutive decode errors. */
138 atomic_set(&phy->decode_error_count, 0);
139 }
140
141 if (emac_sgmii_irq_clear(adpt, status)) {
142 netdev_warn(adpt->netdev, "failed to clear SGMII interrupt\n");
143 schedule_work(&adpt->work_thread);
144 }
145
146 return IRQ_HANDLED;
147}
148
99static void emac_sgmii_reset_prepare(struct emac_adapter *adpt) 149static void emac_sgmii_reset_prepare(struct emac_adapter *adpt)
100{ 150{
101 struct emac_sgmii *phy = &adpt->phy; 151 struct emac_sgmii *phy = &adpt->phy;
@@ -129,6 +179,68 @@ void emac_sgmii_reset(struct emac_adapter *adpt)
129 ret); 179 ret);
130} 180}
131 181
182static int emac_sgmii_open(struct emac_adapter *adpt)
183{
184 struct emac_sgmii *sgmii = &adpt->phy;
185 int ret;
186
187 if (sgmii->irq) {
188 /* Make sure interrupts are cleared and disabled first */
189 ret = emac_sgmii_irq_clear(adpt, 0xff);
190 if (ret)
191 return ret;
192 writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
193
194 ret = request_irq(sgmii->irq, emac_sgmii_interrupt, 0,
195 "emac-sgmii", adpt);
196 if (ret) {
197 netdev_err(adpt->netdev,
198 "could not register handler for internal PHY\n");
199 return ret;
200 }
201 }
202
203 return 0;
204}
205
206static int emac_sgmii_close(struct emac_adapter *adpt)
207{
208 struct emac_sgmii *sgmii = &adpt->phy;
209
210 /* Make sure interrupts are disabled */
211 writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
212 free_irq(sgmii->irq, adpt);
213
214 return 0;
215}
216
217/* The error interrupts are only valid after the link is up */
218static int emac_sgmii_link_up(struct emac_adapter *adpt)
219{
220 struct emac_sgmii *sgmii = &adpt->phy;
221 int ret;
222
223 /* Clear and enable interrupts */
224 ret = emac_sgmii_irq_clear(adpt, 0xff);
225 if (ret)
226 return ret;
227
228 writel(SGMII_ISR_MASK, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
229
230 return 0;
231}
232
233static int emac_sgmii_link_down(struct emac_adapter *adpt)
234{
235 struct emac_sgmii *sgmii = &adpt->phy;
236
237 /* Disable interrupts */
238 writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK);
239 synchronize_irq(sgmii->irq);
240
241 return 0;
242}
243
132static int emac_sgmii_acpi_match(struct device *dev, void *data) 244static int emac_sgmii_acpi_match(struct device *dev, void *data)
133{ 245{
134#ifdef CONFIG_ACPI 246#ifdef CONFIG_ACPI
@@ -139,7 +251,7 @@ static int emac_sgmii_acpi_match(struct device *dev, void *data)
139 {} 251 {}
140 }; 252 };
141 const struct acpi_device_id *id = acpi_match_device(match_table, dev); 253 const struct acpi_device_id *id = acpi_match_device(match_table, dev);
142 emac_sgmii_initialize *initialize = data; 254 emac_sgmii_function *initialize = data;
143 255
144 if (id) { 256 if (id) {
145 acpi_handle handle = ACPI_HANDLE(dev); 257 acpi_handle handle = ACPI_HANDLE(dev);
@@ -226,9 +338,14 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
226 goto error_put_device; 338 goto error_put_device;
227 } 339 }
228 340
229 phy->initialize = (emac_sgmii_initialize)match->data; 341 phy->initialize = (emac_sgmii_function)match->data;
230 } 342 }
231 343
344 phy->open = emac_sgmii_open;
345 phy->close = emac_sgmii_close;
346 phy->link_up = emac_sgmii_link_up;
347 phy->link_down = emac_sgmii_link_down;
348
232 /* Base address is the first address */ 349 /* Base address is the first address */
233 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); 350 res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0);
234 if (!res) { 351 if (!res) {
@@ -256,9 +373,12 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt)
256 if (ret) 373 if (ret)
257 goto error; 374 goto error;
258 375
259 emac_sgmii_irq_clear(adpt, SGMII_PHY_INTERRUPT_ERR);
260 emac_sgmii_link_init(adpt); 376 emac_sgmii_link_init(adpt);
261 377
378 ret = platform_get_irq(sgmii_pdev, 0);
379 if (ret > 0)
380 phy->irq = ret;
381
262 /* We've remapped the addresses, so we don't need the device any 382 /* We've remapped the addresses, so we don't need the device any
263 * more. of_find_device_by_node() says we should release it. 383 * more. of_find_device_by_node() says we should release it.
264 */ 384 */
diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
index 4a8f6b174f4b..e7c0c3b2baa4 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
+++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.h
@@ -16,17 +16,29 @@
16struct emac_adapter; 16struct emac_adapter;
17struct platform_device; 17struct platform_device;
18 18
19typedef int (*emac_sgmii_initialize)(struct emac_adapter *adpt); 19typedef int (*emac_sgmii_function)(struct emac_adapter *adpt);
20 20
21/** emac_sgmii - internal emac phy 21/** emac_sgmii - internal emac phy
22 * @base base address 22 * @base base address
23 * @digital per-lane digital block 23 * @digital per-lane digital block
24 * @irq the interrupt number
25 * @decode_error_count reference count of consecutive decode errors
24 * @initialize initialization function 26 * @initialize initialization function
27 * @open called when the driver is opened
28 * @close called when the driver is closed
29 * @link_up called when the link comes up
30 * @link_down called when the link comes down
25 */ 31 */
26struct emac_sgmii { 32struct emac_sgmii {
27 void __iomem *base; 33 void __iomem *base;
28 void __iomem *digital; 34 void __iomem *digital;
29 emac_sgmii_initialize initialize; 35 unsigned int irq;
36 atomic_t decode_error_count;
37 emac_sgmii_function initialize;
38 emac_sgmii_function open;
39 emac_sgmii_function close;
40 emac_sgmii_function link_up;
41 emac_sgmii_function link_down;
30}; 42};
31 43
32int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt); 44int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt);
diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c
index 75305ad436d5..f519351ef3a2 100644
--- a/drivers/net/ethernet/qualcomm/emac/emac.c
+++ b/drivers/net/ethernet/qualcomm/emac/emac.c
@@ -280,6 +280,14 @@ static int emac_open(struct net_device *netdev)
280 return ret; 280 return ret;
281 } 281 }
282 282
283 ret = adpt->phy.open(adpt);
284 if (ret) {
285 emac_mac_down(adpt);
286 emac_mac_rx_tx_rings_free_all(adpt);
287 free_irq(irq->irq, irq);
288 return ret;
289 }
290
283 return 0; 291 return 0;
284} 292}
285 293
@@ -290,6 +298,7 @@ static int emac_close(struct net_device *netdev)
290 298
291 mutex_lock(&adpt->reset_lock); 299 mutex_lock(&adpt->reset_lock);
292 300
301 adpt->phy.close(adpt);
293 emac_mac_down(adpt); 302 emac_mac_down(adpt);
294 emac_mac_rx_tx_rings_free_all(adpt); 303 emac_mac_rx_tx_rings_free_all(adpt);
295 304
@@ -645,6 +654,7 @@ static int emac_probe(struct platform_device *pdev)
645 adpt->msg_enable = EMAC_MSG_DEFAULT; 654 adpt->msg_enable = EMAC_MSG_DEFAULT;
646 655
647 phy = &adpt->phy; 656 phy = &adpt->phy;
657 atomic_set(&phy->decode_error_count, 0);
648 658
649 mutex_init(&adpt->reset_lock); 659 mutex_init(&adpt->reset_lock);
650 spin_lock_init(&adpt->stats.lock); 660 spin_lock_init(&adpt->stats.lock);