Commit 03a3bdb7a926cf1919e795e7ab196bfefb2a3e7e
Committed by
Priyanka Jain
1 parent
cff1447596
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
net: memac_phy: add a timeout to MDIO operations
We have encountered circumstances when a board design does not include pull-up resistors on the external MDIO buses which are not used. This leads to the MDIO data line not being pulled-up, thus the MDIO controller will always see the line as busy. Without a timeout in the MDIO bus driver, the execution is stuck in an infinite loop when any access is initiated on that external bus. Add a timeout in the driver so that we are protected in this circumstance. This is similar to what is being done in the Linux xgmac_mdio driver. Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Showing 1 changed file with 58 additions and 18 deletions Side-by-side Diff
drivers/net/fm/memac_phy.c
... | ... | @@ -22,6 +22,8 @@ |
22 | 22 | #define memac_setbits_32(a, v) setbits_be32(a, v) |
23 | 23 | #endif |
24 | 24 | |
25 | +#define MAX_NUM_RETRIES 1000 | |
26 | + | |
25 | 27 | static u32 memac_in_32(u32 *reg) |
26 | 28 | { |
27 | 29 | #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN |
... | ... | @@ -32,6 +34,42 @@ |
32 | 34 | } |
33 | 35 | |
34 | 36 | /* |
37 | + * Wait until the MDIO bus is free | |
38 | + */ | |
39 | +static int memac_wait_until_free(struct memac_mdio_controller *regs) | |
40 | +{ | |
41 | + unsigned int timeout = MAX_NUM_RETRIES; | |
42 | + | |
43 | + while ((memac_in_32(®s->mdio_stat) & MDIO_STAT_BSY) && timeout--) | |
44 | + ; | |
45 | + | |
46 | + if (!timeout) { | |
47 | + printf("timeout waiting for MDIO bus to be free\n"); | |
48 | + return -ETIMEDOUT; | |
49 | + } | |
50 | + | |
51 | + return 0; | |
52 | +} | |
53 | + | |
54 | +/* | |
55 | + * Wait till the MDIO read or write operation is complete | |
56 | + */ | |
57 | +static int memac_wait_until_done(struct memac_mdio_controller *regs) | |
58 | +{ | |
59 | + unsigned int timeout = MAX_NUM_RETRIES; | |
60 | + | |
61 | + while ((memac_in_32(®s->mdio_data) & MDIO_DATA_BSY) && timeout--) | |
62 | + ; | |
63 | + | |
64 | + if (!timeout) { | |
65 | + printf("timeout waiting for MDIO operation to complete\n"); | |
66 | + return -ETIMEDOUT; | |
67 | + } | |
68 | + | |
69 | + return 0; | |
70 | +} | |
71 | + | |
72 | +/* | |
35 | 73 | * Write value to the PHY for this device to the register at regnum, waiting |
36 | 74 | * until the write is done before it returns. All PHY configuration has to be |
37 | 75 | * done through the TSEC1 MIIM regs |
... | ... | @@ -42,6 +80,7 @@ |
42 | 80 | u32 mdio_ctl; |
43 | 81 | struct memac_mdio_controller *regs = bus->priv; |
44 | 82 | u32 c45 = 1; /* Default to 10G interface */ |
83 | + int err; | |
45 | 84 | |
46 | 85 | if (dev_addr == MDIO_DEVAD_NONE) { |
47 | 86 | c45 = 0; /* clause 22 */ |
... | ... | @@ -50,9 +89,9 @@ |
50 | 89 | } else |
51 | 90 | memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
52 | 91 | |
53 | - /* Wait till the bus is free */ | |
54 | - while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) | |
55 | - ; | |
92 | + err = memac_wait_until_free(regs); | |
93 | + if (err) | |
94 | + return err; | |
56 | 95 | |
57 | 96 | /* Set the port and dev addr */ |
58 | 97 | mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); |
59 | 98 | |
... | ... | @@ -62,16 +101,16 @@ |
62 | 101 | if (c45) |
63 | 102 | memac_out_32(®s->mdio_addr, regnum & 0xffff); |
64 | 103 | |
65 | - /* Wait till the bus is free */ | |
66 | - while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) | |
67 | - ; | |
104 | + err = memac_wait_until_free(regs); | |
105 | + if (err) | |
106 | + return err; | |
68 | 107 | |
69 | 108 | /* Write the value to the register */ |
70 | 109 | memac_out_32(®s->mdio_data, MDIO_DATA(value)); |
71 | 110 | |
72 | - /* Wait till the MDIO write is complete */ | |
73 | - while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) | |
74 | - ; | |
111 | + err = memac_wait_until_done(regs); | |
112 | + if (err) | |
113 | + return err; | |
75 | 114 | |
76 | 115 | return 0; |
77 | 116 | } |
... | ... | @@ -87,6 +126,7 @@ |
87 | 126 | u32 mdio_ctl; |
88 | 127 | struct memac_mdio_controller *regs = bus->priv; |
89 | 128 | u32 c45 = 1; |
129 | + int err; | |
90 | 130 | |
91 | 131 | if (dev_addr == MDIO_DEVAD_NONE) { |
92 | 132 | if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME)) |
... | ... | @@ -97,9 +137,9 @@ |
97 | 137 | } else |
98 | 138 | memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); |
99 | 139 | |
100 | - /* Wait till the bus is free */ | |
101 | - while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) | |
102 | - ; | |
140 | + err = memac_wait_until_free(regs); | |
141 | + if (err) | |
142 | + return err; | |
103 | 143 | |
104 | 144 | /* Set the Port and Device Addrs */ |
105 | 145 | mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr); |
106 | 146 | |
... | ... | @@ -109,17 +149,17 @@ |
109 | 149 | if (c45) |
110 | 150 | memac_out_32(®s->mdio_addr, regnum & 0xffff); |
111 | 151 | |
112 | - /* Wait till the bus is free */ | |
113 | - while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) | |
114 | - ; | |
152 | + err = memac_wait_until_free(regs); | |
153 | + if (err) | |
154 | + return err; | |
115 | 155 | |
116 | 156 | /* Initiate the read */ |
117 | 157 | mdio_ctl |= MDIO_CTL_READ; |
118 | 158 | memac_out_32(®s->mdio_ctl, mdio_ctl); |
119 | 159 | |
120 | - /* Wait till the MDIO write is complete */ | |
121 | - while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) | |
122 | - ; | |
160 | + err = memac_wait_until_done(regs); | |
161 | + if (err) | |
162 | + return err; | |
123 | 163 | |
124 | 164 | /* Return all Fs if nothing was there */ |
125 | 165 | if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) |