Message ID | 1664648831-7965-3-git-send-email-michael.chan@broadcom.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | bnxt_en: Driver updates | expand |
On Sat, Oct 01, 2022 at 02:27:10PM -0400, Michael Chan wrote: > +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, > + const struct ethtool_module_eeprom *page_data, > + struct netlink_ext_ack *extack) > +{ > + struct bnxt *bp = netdev_priv(dev); > + int rc; > + > + if (bp->link_info.module_status > > + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) { > + NL_SET_ERR_MSG_MOD(extack, "Phy status unknown"); Can you make this more helpful to users? The comment above this check in bnxt_get_module_info() suggests that it is possible: /* No point in going further if phy status indicates * module is not inserted or if it is powered down or * if it is of type 10GBase-T */ if (bp->link_info.module_status > PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) > + return -EIO; > + } > + > + if (bp->hwrm_spec_code < 0x10202) { > + NL_SET_ERR_MSG_MOD(extack, "Unsupported hwrm spec"); Likewise. As a user I do not know what "hwrm spec" means... Maybe: NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); > + return -EOPNOTSUPP; > + } > + > + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { > + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); > + return -EOPNOTSUPP; What happens if you have an old firmware that does not support this functionality and user space tries to dump page 10h from bank 1 of a CMIS module that supports multiple banks? I wanted to say that you would see the wrong information (from bank 0) because the legacy operations do not support banks and bank 0 is assumed. However, because only pages 10h-ffh are banked, user space will get an error from the following check in fallback_set_params(): if (request->page) offset = request->page * ETH_MODULE_EEPROM_PAGE_LEN + offset; [...] if (offset >= modinfo->eeprom_len) return -EINVAL; I believe it makes sense to be more explicit about it and return an error in fallback_set_params() in case bank is not 0. Please follow up if the above analysis is correct. > + } > + > + rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, I was wondering why the shift is needed, but I see that in other places you are passing 0xA0 and 0xA2 instead of 0x50 and 0x51, so it is OK. > + page_data->page, page_data->bank, > + page_data->offset, > + page_data->length, > + page_data->data); > + if (rc) { > + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); > + return rc; > + } > + return page_data->length; > +} Looks good otherwise. Thanks
Hi Ido, On Sun, Oct 2, 2022 at 9:04 PM Ido Schimmel <idosch@idosch.org> wrote: > > On Sat, Oct 01, 2022 at 02:27:10PM -0400, Michael Chan wrote: > > +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, > > + const struct ethtool_module_eeprom *page_data, > > + struct netlink_ext_ack *extack) > > +{ > > + struct bnxt *bp = netdev_priv(dev); > > + int rc; > > + > > + if (bp->link_info.module_status > > > + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) { > > + NL_SET_ERR_MSG_MOD(extack, "Phy status unknown"); > > Can you make this more helpful to users? The comment above this check in > bnxt_get_module_info() suggests that it is possible: Do you mean that we should elaborate something like NL_SET_ERR_MSG_MOD(extack, "Module may be not inserted or powered down or 10G Base-T"); > > /* No point in going further if phy status indicates > * module is not inserted or if it is powered down or > * if it is of type 10GBase-T > */ > if (bp->link_info.module_status > > PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) > > > + return -EIO; > > + } > > + > > + if (bp->hwrm_spec_code < 0x10202) { > > + NL_SET_ERR_MSG_MOD(extack, "Unsupported hwrm spec"); > > Likewise. As a user I do not know what "hwrm spec" means... Maybe: > > NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); > > > > + return -EOPNOTSUPP; > > + } > > + > > + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { > > + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); > > + return -EOPNOTSUPP; > > What happens if you have an old firmware that does not support this > functionality and user space tries to dump page 10h from bank 1 of a > CMIS module that supports multiple banks? > > I wanted to say that you would see the wrong information (from bank 0) > because the legacy operations do not support banks and bank 0 is > assumed. However, because only pages 10h-ffh are banked, user space will > get an error from the following check in fallback_set_params(): > > if (request->page) > offset = request->page * ETH_MODULE_EEPROM_PAGE_LEN + offset; > > [...] > > if (offset >= modinfo->eeprom_len) > return -EINVAL; > > I believe it makes sense to be more explicit about it and return an > error in fallback_set_params() in case bank is not 0. Please follow up > if the above analysis is correct. So older firmware do not understand bank > 0 and hence it returns to EOPNOTSUPP, which goes to fallback_set_params() and fails for if (offset >= modinfo->eeprom_len) return -EINVAL As we are not setting modinfo->eeprom_len for CMIS modules in get_module_eeprom. With the above said userspace gets EINVAL. Let me know if my understanding is correct? Thanks, Vikas > > > + } > > + > > + rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, > > I was wondering why the shift is needed, but I see that in other places > you are passing 0xA0 and 0xA2 instead of 0x50 and 0x51, so it is OK. > > > + page_data->page, page_data->bank, > > + page_data->offset, > > + page_data->length, > > + page_data->data); > > + if (rc) { > > + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); > > + return rc; > > + } > > + return page_data->length; > > +} > > Looks good otherwise. > > Thanks
On Sun, Oct 02, 2022 at 09:51:10PM +0530, Vikas Gupta wrote: > On Sun, Oct 2, 2022 at 9:04 PM Ido Schimmel <idosch@idosch.org> wrote: > > > > On Sat, Oct 01, 2022 at 02:27:10PM -0400, Michael Chan wrote: > > > +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, > > > + const struct ethtool_module_eeprom *page_data, > > > + struct netlink_ext_ack *extack) > > > +{ > > > + struct bnxt *bp = netdev_priv(dev); > > > + int rc; > > > + > > > + if (bp->link_info.module_status > > > > + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) { > > > + NL_SET_ERR_MSG_MOD(extack, "Phy status unknown"); > > > > Can you make this more helpful to users? The comment above this check in > > bnxt_get_module_info() suggests that it is possible: > > Do you mean that we should elaborate something like > NL_SET_ERR_MSG_MOD(extack, "Module may be not inserted or powered down > or 10G Base-T"); Yes, but even then the exact error is unknown and you would need something like drgn / kprobes to retrieve the specific module_state for debug. You can do something like the following (in a separate function): if (bp->link_info.module_status <= PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) return 0; switch (bp->link_info.module_status) { case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); break; case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); break; case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: NL_SET_ERR_MSG_MOD(extack, "... something that explains what this means ..."); break; default: NL_SET_ERR_MSG_MOD(extack, "Unknown error"); break; } return -EINVAL; > > > > > /* No point in going further if phy status indicates > > * module is not inserted or if it is powered down or > > * if it is of type 10GBase-T > > */ > > if (bp->link_info.module_status > > > PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) > > > > > + return -EIO; > > > + } > > > + > > > + if (bp->hwrm_spec_code < 0x10202) { > > > + NL_SET_ERR_MSG_MOD(extack, "Unsupported hwrm spec"); > > > > Likewise. As a user I do not know what "hwrm spec" means... Maybe: > > > > NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); > > > > > > > + return -EOPNOTSUPP; > > > + } > > > + > > > + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { > > > + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); > > > + return -EOPNOTSUPP; > > > > What happens if you have an old firmware that does not support this > > functionality and user space tries to dump page 10h from bank 1 of a > > CMIS module that supports multiple banks? > > > > I wanted to say that you would see the wrong information (from bank 0) > > because the legacy operations do not support banks and bank 0 is > > assumed. However, because only pages 10h-ffh are banked, user space will > > get an error from the following check in fallback_set_params(): > > > > if (request->page) > > offset = request->page * ETH_MODULE_EEPROM_PAGE_LEN + offset; > > > > [...] > > > > if (offset >= modinfo->eeprom_len) > > return -EINVAL; > > > > I believe it makes sense to be more explicit about it and return an > > error in fallback_set_params() in case bank is not 0. Please follow up > > if the above analysis is correct. > > So older firmware do not understand bank > 0 and hence it returns to > EOPNOTSUPP, which goes to fallback_set_params() and fails for > if (offset >= modinfo->eeprom_len) > return -EINVAL > As we are not setting modinfo->eeprom_len for CMIS modules in get_module_eeprom. > With the above said userspace gets EINVAL. > Let me know if my understanding is correct? Yes. Basically there is no point for ethtool to even try to invoke the legacy operations when bank is not zero: diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c index 1c94bb8ea03f..1d6a35c8b6f0 100644 --- a/net/ethtool/eeprom.c +++ b/net/ethtool/eeprom.c @@ -60,6 +60,9 @@ static int eeprom_fallback(struct eeprom_req_info *request, u8 *data; int err; + if (request->bank) + return -EINVAL; + modinfo.cmd = ETHTOOL_GMODULEINFO; err = ethtool_get_module_info_call(dev, &modinfo); if (err < 0) Not sure how many will actually hit it. I expect drivers supporting modules with banked pages to implement the new ethtool operation.
Hi Ido, On Mon, Oct 3, 2022 at 12:49 PM Ido Schimmel <idosch@idosch.org> wrote: > > On Sun, Oct 02, 2022 at 09:51:10PM +0530, Vikas Gupta wrote: > > On Sun, Oct 2, 2022 at 9:04 PM Ido Schimmel <idosch@idosch.org> wrote: > > > > > > On Sat, Oct 01, 2022 at 02:27:10PM -0400, Michael Chan wrote: > > > > +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, > > > > + const struct ethtool_module_eeprom *page_data, > > > > + struct netlink_ext_ack *extack) > > > > +{ > > > > + struct bnxt *bp = netdev_priv(dev); > > > > + int rc; > > > > + > > > > + if (bp->link_info.module_status > > > > > + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) { > > > > + NL_SET_ERR_MSG_MOD(extack, "Phy status unknown"); > > > > > > Can you make this more helpful to users? The comment above this check in > > > bnxt_get_module_info() suggests that it is possible: > > > > Do you mean that we should elaborate something like > > NL_SET_ERR_MSG_MOD(extack, "Module may be not inserted or powered down > > or 10G Base-T"); > > Yes, but even then the exact error is unknown and you would need > something like drgn / kprobes to retrieve the specific module_state for > debug. You can do something like the following (in a separate function): > > if (bp->link_info.module_status <= > PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) > return 0; > > switch (bp->link_info.module_status) { > case PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN: > NL_SET_ERR_MSG_MOD(extack, "Transceiver module is powering down"); > break; > case PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED: > NL_SET_ERR_MSG_MOD(extack, "Transceiver module not inserted"); > break; > case PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT: > NL_SET_ERR_MSG_MOD(extack, "... something that explains what this means ..."); > break; > default: > NL_SET_ERR_MSG_MOD(extack, "Unknown error"); > break; > } We`ll try to provide more appropriate information above. > > return -EINVAL; > > > > > > > > > /* No point in going further if phy status indicates > > > * module is not inserted or if it is powered down or > > > * if it is of type 10GBase-T > > > */ > > > if (bp->link_info.module_status > > > > PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) > > > > > > > + return -EIO; > > > > + } > > > > + > > > > + if (bp->hwrm_spec_code < 0x10202) { > > > > + NL_SET_ERR_MSG_MOD(extack, "Unsupported hwrm spec"); > > > > > > Likewise. As a user I do not know what "hwrm spec" means... Maybe: > > > > > > NL_SET_ERR_MSG_MOD(extack, "Firmware version too old"); > > > > > > > > > > + return -EOPNOTSUPP; > > > > + } > > > > + > > > > + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { > > > > + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); > > > > + return -EOPNOTSUPP; > > > > > > What happens if you have an old firmware that does not support this > > > functionality and user space tries to dump page 10h from bank 1 of a > > > CMIS module that supports multiple banks? > > > > > > I wanted to say that you would see the wrong information (from bank 0) > > > because the legacy operations do not support banks and bank 0 is > > > assumed. However, because only pages 10h-ffh are banked, user space will > > > get an error from the following check in fallback_set_params(): > > > > > > if (request->page) > > > offset = request->page * ETH_MODULE_EEPROM_PAGE_LEN + offset; > > > > > > [...] > > > > > > if (offset >= modinfo->eeprom_len) > > > return -EINVAL; > > > > > > I believe it makes sense to be more explicit about it and return an > > > error in fallback_set_params() in case bank is not 0. Please follow up > > > if the above analysis is correct. > > > > So older firmware do not understand bank > 0 and hence it returns to > > EOPNOTSUPP, which goes to fallback_set_params() and fails for > > if (offset >= modinfo->eeprom_len) > > return -EINVAL > > As we are not setting modinfo->eeprom_len for CMIS modules in get_module_eeprom. > > With the above said userspace gets EINVAL. > > Let me know if my understanding is correct? > > Yes. Basically there is no point for ethtool to even try to invoke the > legacy operations when bank is not zero: > > diff --git a/net/ethtool/eeprom.c b/net/ethtool/eeprom.c > index 1c94bb8ea03f..1d6a35c8b6f0 100644 > --- a/net/ethtool/eeprom.c > +++ b/net/ethtool/eeprom.c > @@ -60,6 +60,9 @@ static int eeprom_fallback(struct eeprom_req_info *request, > u8 *data; > int err; > > + if (request->bank) > + return -EINVAL; > + > modinfo.cmd = ETHTOOL_GMODULEINFO; > err = ethtool_get_module_info_call(dev, &modinfo); > if (err < 0) > > Not sure how many will actually hit it. I expect drivers supporting > modules with banked pages to implement the new ethtool operation. We may return with -EINVAL so it wont fallback but I like your suggestion for bank check in eeprom_fallback if (request->bank) return -EINVAL; seems to be a good idea as the bank parameter is not propagating further to the drivers. I believe your new operation means that "drivers need to implement get_module_eeprom_by_page" if they want to access banked pages. Am I right? Thanks, Vikas
On Mon, Oct 03, 2022 at 02:55:13PM +0530, Vikas Gupta wrote: > I believe your new operation means that "drivers need to implement > get_module_eeprom_by_page" if they want to access banked pages. Am I > right? Yes
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index b1b17f911300..91a1ba0a914d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2116,6 +2116,7 @@ struct bnxt { #define BNXT_PHY_FL_NO_FCS PORT_PHY_QCAPS_RESP_FLAGS_NO_FCS #define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8) #define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8) +#define BNXT_PHY_FL_BANK_SEL (PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED << 8) u8 num_tests; struct bnxt_test_info *test_info; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index f57e524c7e30..092cd4f98a6d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3146,8 +3146,9 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) } static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, - u16 page_number, u16 start_addr, - u16 data_length, u8 *buf) + u16 page_number, u8 bank, + u16 start_addr, u16 data_length, + u8 *buf) { struct hwrm_port_phy_i2c_read_output *output; struct hwrm_port_phy_i2c_read_input *req; @@ -3168,8 +3169,13 @@ static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr, data_length -= xfer_size; req->page_offset = cpu_to_le16(start_addr + byte_offset); req->data_length = xfer_size; - req->enables = cpu_to_le32(start_addr + byte_offset ? - PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0); + req->enables = + cpu_to_le32((start_addr + byte_offset ? + PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : + 0) | + (bank ? + PORT_PHY_I2C_READ_REQ_ENABLES_BANK_NUMBER : + 0)); rc = hwrm_req_send(bp, req); if (!rc) memcpy(buf + byte_offset, output->data, xfer_size); @@ -3199,7 +3205,7 @@ static int bnxt_get_module_info(struct net_device *dev, if (bp->hwrm_spec_code < 0x10202) return -EOPNOTSUPP; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, 0, SFF_DIAG_SUPPORT_OFFSET + 1, data); if (!rc) { @@ -3244,7 +3250,7 @@ static int bnxt_get_module_eeprom(struct net_device *dev, if (start < ETH_MODULE_SFF_8436_LEN) { if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN) length = ETH_MODULE_SFF_8436_LEN - start; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0, start, length, data); if (rc) return rc; @@ -3256,12 +3262,47 @@ static int bnxt_get_module_eeprom(struct net_device *dev, /* Read A2 portion of the EEPROM */ if (length) { start -= ETH_MODULE_SFF_8436_LEN; - rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, + rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0, 0, start, length, data); } return rc; } +static int bnxt_get_module_eeprom_by_page(struct net_device *dev, + const struct ethtool_module_eeprom *page_data, + struct netlink_ext_ack *extack) +{ + struct bnxt *bp = netdev_priv(dev); + int rc; + + if (bp->link_info.module_status > + PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG) { + NL_SET_ERR_MSG_MOD(extack, "Phy status unknown"); + return -EIO; + } + + if (bp->hwrm_spec_code < 0x10202) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported hwrm spec"); + return -EOPNOTSUPP; + } + + if (page_data->bank && !(bp->phy_flags & BNXT_PHY_FL_BANK_SEL)) { + NL_SET_ERR_MSG_MOD(extack, "Firmware not capable for bank selection"); + return -EOPNOTSUPP; + } + + rc = bnxt_read_sfp_module_eeprom_info(bp, page_data->i2c_address << 1, + page_data->page, page_data->bank, + page_data->offset, + page_data->length, + page_data->data); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Module`s eeprom read failed"); + return rc; + } + return page_data->length; +} + static int bnxt_nway_reset(struct net_device *dev) { int rc = 0; @@ -4071,6 +4112,7 @@ const struct ethtool_ops bnxt_ethtool_ops = { .set_eee = bnxt_set_eee, .get_module_info = bnxt_get_module_info, .get_module_eeprom = bnxt_get_module_eeprom, + .get_module_eeprom_by_page = bnxt_get_module_eeprom_by_page, .nway_reset = bnxt_nway_reset, .set_phys_id = bnxt_set_phys_id, .self_test = bnxt_self_test,