From: Bjorn Andersson <bjorn.andersson@linaro.org> To: "David S. Miller" <davem@davemloft.net>, Chuhong Yuan <hslester96@gmail.com>, Peter Fink <pfink@christ-es.de> Cc: linux-usb@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org Subject: [PATCH] net: usb: ax88179_178a: Implement ethtool_ops set_eeprom Date: Tue, 28 Apr 2020 00:01:39 -0700 Message-ID: <20200428070139.3465511-1-bjorn.andersson@linaro.org> (raw) The vendor driver does upon failing to read a valid MAC address from EEPROM write the netdev's address back to EEPROM and invoking a EEPROM reload operation. Based on this we can implement the ethtool_ops set_eeprom and provide the means to populate the EEPROM from within Linux. It's worth noting that ax88179_get_eeprom() will return some default data unless the content of the EEPROM is deemed "complete", so until the EEPROM is fully populated (e.g. by running ethtool -e | ethtool -E) data written with ax88179_set_eeprom() will appear not to stick. The implementation is based on asix_set_eeprom(), from asix_common.c Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> --- drivers/net/usb/ax88179_178a.c | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 93044cf1417a..b05bb11a02cb 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -31,6 +31,7 @@ #define AX_ACCESS_PHY 0x02 #define AX_ACCESS_EEPROM 0x04 #define AX_ACCESS_EFUS 0x05 +#define AX_RELOAD_EEPROM_EFUSE 0x06 #define AX_PAUSE_WATERLVL_HIGH 0x54 #define AX_PAUSE_WATERLVL_LOW 0x55 @@ -611,6 +612,81 @@ ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, return 0; } +static int +ax88179_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, + u8 *data) +{ + struct usbnet *dev = netdev_priv(net); + u16 *eeprom_buff; + int first_word; + int last_word; + int ret; + int i; + + netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n", + eeprom->len, eeprom->offset, eeprom->magic); + + if (eeprom->len == 0) + return -EINVAL; + + if (eeprom->magic != AX88179_EEPROM_MAGIC) + return -EINVAL; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), + GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + /* align data to 16 bit boundaries, read the missing data from + the EEPROM */ + if (eeprom->offset & 1) { + ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM, first_word, 1, 2, + &eeprom_buff[0]); + if (ret < 0) { + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); + goto free; + } + } + + if ((eeprom->offset + eeprom->len) & 1) { + ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM, last_word, 1, 2, + &eeprom_buff[last_word - first_word]); + if (ret < 0) { + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); + goto free; + } + } + + memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); + + for (i = first_word; i <= last_word; i++) { + netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", + i, eeprom_buff[i - first_word]); + ret = ax88179_write_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2, + &eeprom_buff[i - first_word]); + if (ret < 0) { + netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", i); + goto free; + } + msleep(20); + } + + /* reload EEPROM data */ + ret = ax88179_write_cmd(dev, AX_RELOAD_EEPROM_EFUSE, 0x0000, 0, 0, NULL); + if (ret < 0) { + netdev_err(net, "Failed to reload EEPROM data\n"); + goto free; + } + + ret = 0; +free: + kfree(eeprom_buff); + return ret; +} + static int ax88179_get_link_ksettings(struct net_device *net, struct ethtool_link_ksettings *cmd) { @@ -822,6 +898,7 @@ static const struct ethtool_ops ax88179_ethtool_ops = { .set_wol = ax88179_set_wol, .get_eeprom_len = ax88179_get_eeprom_len, .get_eeprom = ax88179_get_eeprom, + .set_eeprom = ax88179_set_eeprom, .get_eee = ax88179_get_eee, .set_eee = ax88179_set_eee, .nway_reset = usbnet_nway_reset, -- 2.24.0
reply index Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20200428070139.3465511-1-bjorn.andersson@linaro.org \ --to=bjorn.andersson@linaro.org \ --cc=davem@davemloft.net \ --cc=hslester96@gmail.com \ --cc=linux-arm-msm@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-usb@vger.kernel.org \ --cc=netdev@vger.kernel.org \ --cc=pfink@christ-es.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Linux-ARM-MSM Archive on lore.kernel.org Archives are clonable: git clone --mirror https://lore.kernel.org/linux-arm-msm/0 linux-arm-msm/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 linux-arm-msm linux-arm-msm/ https://lore.kernel.org/linux-arm-msm \ linux-arm-msm@vger.kernel.org public-inbox-index linux-arm-msm Example config snippet for mirrors Newsgroup available over NNTP: nntp://nntp.lore.kernel.org/org.kernel.vger.linux-arm-msm AGPL code for this site: git clone https://public-inbox.org/public-inbox.git