aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Whitehead <Bryan.Whitehead@microchip.com>2019-01-23 15:18:47 -0500
committerDavid S. Miller <davem@davemloft.net>2019-01-26 12:35:21 -0500
commit662a14d0c71e9e775383b0fd6796c9eb47d29ecc (patch)
tree0a9c531ce33f619435954a7a81d2864385dfb144
parent08c666b7033d72038f3dca1478b0d368aa4d0233 (diff)
lan743x: Provide Read/Write Access to on chip OTP
The LAN743x includes on chip One-Time-Programmable (OTP) memory. This patch extends the ethtool EEPROM read/write interface to access OTP memory space. The currently existing interface is limited, as it does not allow OTP read, and OTP writes are restricted to offset==0, length==512, and data[0]==0xF3. This patch removes these restrictions and adds a private flag called OTP_ACCESS, which is used to switch between EEPROM, and OTP modes. The private flag OTP_ACCESS is configurable through the ethtool --set-priv-flags command. And visible through the ethtool --show-priv-flags command. By default OTP_ACCESS is false, and there for previously existing EEPROM commands will work exactly the same. However now access to OTP requires one extra step of setting OTP_ACCESS to true. This flag controls the read, write, and length reporting, functions of ethtool. EEPROM presence is not checked when setting or clearing this flag. If the EEPROM is not present, the user, as before, will need to diagnose that using existing read and write function of ethtool, while OTP_ACCESS is false. Updates for V2: Added comments as to why this patch is needed. Added comments explaining that EEPROM presence is not check when setting or clearing the OTP_ACCESS flag. Added length checking to all otp/eeprom read/write functions. Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/microchip/lan743x_ethtool.c217
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.h17
2 files changed, 182 insertions, 52 deletions
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 07c1eb63415a..3a0b289d9771 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -14,61 +14,138 @@
14#define EEPROM_INDICATOR_1 (0xA5) 14#define EEPROM_INDICATOR_1 (0xA5)
15#define EEPROM_INDICATOR_2 (0xAA) 15#define EEPROM_INDICATOR_2 (0xAA)
16#define EEPROM_MAC_OFFSET (0x01) 16#define EEPROM_MAC_OFFSET (0x01)
17#define MAX_EEPROM_SIZE 512 17#define MAX_EEPROM_SIZE (512)
18#define MAX_OTP_SIZE (1024)
18#define OTP_INDICATOR_1 (0xF3) 19#define OTP_INDICATOR_1 (0xF3)
19#define OTP_INDICATOR_2 (0xF7) 20#define OTP_INDICATOR_2 (0xF7)
20 21
21static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset, 22static int lan743x_otp_power_up(struct lan743x_adapter *adapter)
22 u32 length, u8 *data) 23{
24 u32 reg_value;
25
26 reg_value = lan743x_csr_read(adapter, OTP_PWR_DN);
27
28 if (reg_value & OTP_PWR_DN_PWRDN_N_) {
29 /* clear it and wait to be cleared */
30 reg_value &= ~OTP_PWR_DN_PWRDN_N_;
31 lan743x_csr_write(adapter, OTP_PWR_DN, reg_value);
32
33 usleep_range(100, 20000);
34 }
35
36 return 0;
37}
38
39static void lan743x_otp_power_down(struct lan743x_adapter *adapter)
40{
41 u32 reg_value;
42
43 reg_value = lan743x_csr_read(adapter, OTP_PWR_DN);
44 if (!(reg_value & OTP_PWR_DN_PWRDN_N_)) {
45 /* set power down bit */
46 reg_value |= OTP_PWR_DN_PWRDN_N_;
47 lan743x_csr_write(adapter, OTP_PWR_DN, reg_value);
48 }
49}
50
51static void lan743x_otp_set_address(struct lan743x_adapter *adapter,
52 u32 address)
53{
54 lan743x_csr_write(adapter, OTP_ADDR_HIGH, (address >> 8) & 0x03);
55 lan743x_csr_write(adapter, OTP_ADDR_LOW, address & 0xFF);
56}
57
58static void lan743x_otp_read_go(struct lan743x_adapter *adapter)
59{
60 lan743x_csr_write(adapter, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_);
61 lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_);
62}
63
64static int lan743x_otp_wait_till_not_busy(struct lan743x_adapter *adapter)
23{ 65{
24 unsigned long timeout; 66 unsigned long timeout;
25 u32 buf; 67 u32 reg_val;
68
69 timeout = jiffies + HZ;
70 do {
71 if (time_after(jiffies, timeout)) {
72 netif_warn(adapter, drv, adapter->netdev,
73 "Timeout on OTP_STATUS completion\n");
74 return -EIO;
75 }
76 udelay(1);
77 reg_val = lan743x_csr_read(adapter, OTP_STATUS);
78 } while (reg_val & OTP_STATUS_BUSY_);
79
80 return 0;
81}
82
83static int lan743x_otp_read(struct lan743x_adapter *adapter, u32 offset,
84 u32 length, u8 *data)
85{
86 int ret;
26 int i; 87 int i;
27 88
28 buf = lan743x_csr_read(adapter, OTP_PWR_DN); 89 if (offset + length > MAX_OTP_SIZE)
90 return -EINVAL;
29 91
30 if (buf & OTP_PWR_DN_PWRDN_N_) { 92 ret = lan743x_otp_power_up(adapter);
31 /* clear it and wait to be cleared */ 93 if (ret < 0)
32 lan743x_csr_write(adapter, OTP_PWR_DN, 0); 94 return ret;
33 95
34 timeout = jiffies + HZ; 96 ret = lan743x_otp_wait_till_not_busy(adapter);
35 do { 97 if (ret < 0)
36 udelay(1); 98 return ret;
37 buf = lan743x_csr_read(adapter, OTP_PWR_DN); 99
38 if (time_after(jiffies, timeout)) { 100 for (i = 0; i < length; i++) {
39 netif_warn(adapter, drv, adapter->netdev, 101 lan743x_otp_set_address(adapter, offset + i);
40 "timeout on OTP_PWR_DN completion\n"); 102
41 return -EIO; 103 lan743x_otp_read_go(adapter);
42 } 104 ret = lan743x_otp_wait_till_not_busy(adapter);
43 } while (buf & OTP_PWR_DN_PWRDN_N_); 105 if (ret < 0)
106 return ret;
107 data[i] = lan743x_csr_read(adapter, OTP_READ_DATA);
44 } 108 }
45 109
110 lan743x_otp_power_down(adapter);
111
112 return 0;
113}
114
115static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset,
116 u32 length, u8 *data)
117{
118 int ret;
119 int i;
120
121 if (offset + length > MAX_OTP_SIZE)
122 return -EINVAL;
123
124 ret = lan743x_otp_power_up(adapter);
125 if (ret < 0)
126 return ret;
127
128 ret = lan743x_otp_wait_till_not_busy(adapter);
129 if (ret < 0)
130 return ret;
131
46 /* set to BYTE program mode */ 132 /* set to BYTE program mode */
47 lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_); 133 lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
48 134
49 for (i = 0; i < length; i++) { 135 for (i = 0; i < length; i++) {
50 lan743x_csr_write(adapter, OTP_ADDR1, 136 lan743x_otp_set_address(adapter, offset + i);
51 ((offset + i) >> 8) & 137
52 OTP_ADDR1_15_11_MASK_);
53 lan743x_csr_write(adapter, OTP_ADDR2,
54 ((offset + i) &
55 OTP_ADDR2_10_3_MASK_));
56 lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]); 138 lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]);
57 lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_); 139 lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
58 lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_); 140 lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_);
59 141
60 timeout = jiffies + HZ; 142 ret = lan743x_otp_wait_till_not_busy(adapter);
61 do { 143 if (ret < 0)
62 udelay(1); 144 return ret;
63 buf = lan743x_csr_read(adapter, OTP_STATUS);
64 if (time_after(jiffies, timeout)) {
65 netif_warn(adapter, drv, adapter->netdev,
66 "Timeout on OTP_STATUS completion\n");
67 return -EIO;
68 }
69 } while (buf & OTP_STATUS_BUSY_);
70 } 145 }
71 146
147 lan743x_otp_power_down(adapter);
148
72 return 0; 149 return 0;
73} 150}
74 151
@@ -120,6 +197,9 @@ static int lan743x_eeprom_read(struct lan743x_adapter *adapter,
120 u32 val; 197 u32 val;
121 int i; 198 int i;
122 199
200 if (offset + length > MAX_EEPROM_SIZE)
201 return -EINVAL;
202
123 retval = lan743x_eeprom_confirm_not_busy(adapter); 203 retval = lan743x_eeprom_confirm_not_busy(adapter);
124 if (retval) 204 if (retval)
125 return retval; 205 return retval;
@@ -148,6 +228,9 @@ static int lan743x_eeprom_write(struct lan743x_adapter *adapter,
148 u32 val; 228 u32 val;
149 int i; 229 int i;
150 230
231 if (offset + length > MAX_EEPROM_SIZE)
232 return -EINVAL;
233
151 retval = lan743x_eeprom_confirm_not_busy(adapter); 234 retval = lan743x_eeprom_confirm_not_busy(adapter);
152 if (retval) 235 if (retval)
153 return retval; 236 return retval;
@@ -207,6 +290,11 @@ static void lan743x_ethtool_set_msglevel(struct net_device *netdev,
207 290
208static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev) 291static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev)
209{ 292{
293 struct lan743x_adapter *adapter = netdev_priv(netdev);
294
295 if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP)
296 return MAX_OTP_SIZE;
297
210 return MAX_EEPROM_SIZE; 298 return MAX_EEPROM_SIZE;
211} 299}
212 300
@@ -214,8 +302,14 @@ static int lan743x_ethtool_get_eeprom(struct net_device *netdev,
214 struct ethtool_eeprom *ee, u8 *data) 302 struct ethtool_eeprom *ee, u8 *data)
215{ 303{
216 struct lan743x_adapter *adapter = netdev_priv(netdev); 304 struct lan743x_adapter *adapter = netdev_priv(netdev);
305 int ret = 0;
306
307 if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP)
308 ret = lan743x_otp_read(adapter, ee->offset, ee->len, data);
309 else
310 ret = lan743x_eeprom_read(adapter, ee->offset, ee->len, data);
217 311
218 return lan743x_eeprom_read(adapter, ee->offset, ee->len, data); 312 return ret;
219} 313}
220 314
221static int lan743x_ethtool_set_eeprom(struct net_device *netdev, 315static int lan743x_ethtool_set_eeprom(struct net_device *netdev,
@@ -224,17 +318,18 @@ static int lan743x_ethtool_set_eeprom(struct net_device *netdev,
224 struct lan743x_adapter *adapter = netdev_priv(netdev); 318 struct lan743x_adapter *adapter = netdev_priv(netdev);
225 int ret = -EINVAL; 319 int ret = -EINVAL;
226 320
227 if (ee->magic == LAN743X_EEPROM_MAGIC) 321 if (adapter->flags & LAN743X_ADAPTER_FLAG_OTP) {
228 ret = lan743x_eeprom_write(adapter, ee->offset, ee->len, 322 /* Beware! OTP is One Time Programming ONLY! */
229 data); 323 if (ee->magic == LAN743X_OTP_MAGIC) {
230 /* Beware! OTP is One Time Programming ONLY! 324 ret = lan743x_otp_write(adapter, ee->offset,
231 * So do some strict condition check before messing up 325 ee->len, data);
232 */ 326 }
233 else if ((ee->magic == LAN743X_OTP_MAGIC) && 327 } else {
234 (ee->offset == 0) && 328 if (ee->magic == LAN743X_EEPROM_MAGIC) {
235 (ee->len == MAX_EEPROM_SIZE) && 329 ret = lan743x_eeprom_write(adapter, ee->offset,
236 (data[0] == OTP_INDICATOR_1)) 330 ee->len, data);
237 ret = lan743x_otp_write(adapter, ee->offset, ee->len, data); 331 }
332 }
238 333
239 return ret; 334 return ret;
240} 335}
@@ -360,6 +455,10 @@ static const u32 lan743x_set2_hw_cnt_addr[] = {
360 STAT_TX_COUNTER_ROLLOVER_STATUS 455 STAT_TX_COUNTER_ROLLOVER_STATUS
361}; 456};
362 457
458static const char lan743x_priv_flags_strings[][ETH_GSTRING_LEN] = {
459 "OTP_ACCESS",
460};
461
363static void lan743x_ethtool_get_strings(struct net_device *netdev, 462static void lan743x_ethtool_get_strings(struct net_device *netdev,
364 u32 stringset, u8 *data) 463 u32 stringset, u8 *data)
365{ 464{
@@ -375,6 +474,10 @@ static void lan743x_ethtool_get_strings(struct net_device *netdev,
375 lan743x_set2_hw_cnt_strings, 474 lan743x_set2_hw_cnt_strings,
376 sizeof(lan743x_set2_hw_cnt_strings)); 475 sizeof(lan743x_set2_hw_cnt_strings));
377 break; 476 break;
477 case ETH_SS_PRIV_FLAGS:
478 memcpy(data, lan743x_priv_flags_strings,
479 sizeof(lan743x_priv_flags_strings));
480 break;
378 } 481 }
379} 482}
380 483
@@ -399,6 +502,22 @@ static void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev,
399 } 502 }
400} 503}
401 504
505static u32 lan743x_ethtool_get_priv_flags(struct net_device *netdev)
506{
507 struct lan743x_adapter *adapter = netdev_priv(netdev);
508
509 return adapter->flags;
510}
511
512static int lan743x_ethtool_set_priv_flags(struct net_device *netdev, u32 flags)
513{
514 struct lan743x_adapter *adapter = netdev_priv(netdev);
515
516 adapter->flags = flags;
517
518 return 0;
519}
520
402static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset) 521static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
403{ 522{
404 switch (sset) { 523 switch (sset) {
@@ -411,6 +530,8 @@ static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
411 ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings); 530 ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings);
412 return ret; 531 return ret;
413 } 532 }
533 case ETH_SS_PRIV_FLAGS:
534 return ARRAY_SIZE(lan743x_priv_flags_strings);
414 default: 535 default:
415 return -EOPNOTSUPP; 536 return -EOPNOTSUPP;
416 } 537 }
@@ -705,6 +826,8 @@ const struct ethtool_ops lan743x_ethtool_ops = {
705 .set_eeprom = lan743x_ethtool_set_eeprom, 826 .set_eeprom = lan743x_ethtool_set_eeprom,
706 .get_strings = lan743x_ethtool_get_strings, 827 .get_strings = lan743x_ethtool_get_strings,
707 .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats, 828 .get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
829 .get_priv_flags = lan743x_ethtool_get_priv_flags,
830 .set_priv_flags = lan743x_ethtool_set_priv_flags,
708 .get_sset_count = lan743x_ethtool_get_sset_count, 831 .get_sset_count = lan743x_ethtool_get_sset_count,
709 .get_rxnfc = lan743x_ethtool_get_rxnfc, 832 .get_rxnfc = lan743x_ethtool_get_rxnfc,
710 .get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size, 833 .get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size,
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 2d6eea18973e..3b02eeae5f45 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -26,6 +26,8 @@
26#define FPGA_REV_GET_MAJOR_(fpga_rev) ((fpga_rev) & 0x000000FF) 26#define FPGA_REV_GET_MAJOR_(fpga_rev) ((fpga_rev) & 0x000000FF)
27 27
28#define HW_CFG (0x010) 28#define HW_CFG (0x010)
29#define HW_CFG_RELOAD_TYPE_ALL_ (0x00000FC0)
30#define HW_CFG_EE_OTP_RELOAD_ BIT(4)
29#define HW_CFG_LRST_ BIT(1) 31#define HW_CFG_LRST_ BIT(1)
30 32
31#define PMT_CTL (0x014) 33#define PMT_CTL (0x014)
@@ -453,17 +455,19 @@
453#define OTP_PWR_DN (0x1000) 455#define OTP_PWR_DN (0x1000)
454#define OTP_PWR_DN_PWRDN_N_ BIT(0) 456#define OTP_PWR_DN_PWRDN_N_ BIT(0)
455 457
456#define OTP_ADDR1 (0x1004) 458#define OTP_ADDR_HIGH (0x1004)
457#define OTP_ADDR1_15_11_MASK_ (0x1F) 459#define OTP_ADDR_LOW (0x1008)
458
459#define OTP_ADDR2 (0x1008)
460#define OTP_ADDR2_10_3_MASK_ (0xFF)
461 460
462#define OTP_PRGM_DATA (0x1010) 461#define OTP_PRGM_DATA (0x1010)
463 462
464#define OTP_PRGM_MODE (0x1014) 463#define OTP_PRGM_MODE (0x1014)
465#define OTP_PRGM_MODE_BYTE_ BIT(0) 464#define OTP_PRGM_MODE_BYTE_ BIT(0)
466 465
466#define OTP_READ_DATA (0x1018)
467
468#define OTP_FUNC_CMD (0x1020)
469#define OTP_FUNC_CMD_READ_ BIT(0)
470
467#define OTP_TST_CMD (0x1024) 471#define OTP_TST_CMD (0x1024)
468#define OTP_TST_CMD_PRGVRFY_ BIT(3) 472#define OTP_TST_CMD_PRGVRFY_ BIT(3)
469 473
@@ -713,6 +717,9 @@ struct lan743x_adapter {
713 struct lan743x_phy phy; 717 struct lan743x_phy phy;
714 struct lan743x_tx tx[LAN743X_MAX_TX_CHANNELS]; 718 struct lan743x_tx tx[LAN743X_MAX_TX_CHANNELS];
715 struct lan743x_rx rx[LAN743X_MAX_RX_CHANNELS]; 719 struct lan743x_rx rx[LAN743X_MAX_RX_CHANNELS];
720
721#define LAN743X_ADAPTER_FLAG_OTP BIT(0)
722 u32 flags;
716}; 723};
717 724
718#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel)) 725#define LAN743X_COMPONENT_FLAG_RX(channel) BIT(20 + (channel))