diff options
Diffstat (limited to 'drivers/net/ethernet/aquantia/atlantic')
17 files changed, 347 insertions, 53 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index 8ebcc68e807f..f6a96931c89a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_AQTION) += atlantic.o -ccflags-y += -I$(srctree)/$(src) +ccflags-y += -I$(src) atlantic-objs := aq_main.o \ aq_nic.o \ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 7e9c74b141ef..fc2b325f34e7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -17,7 +17,7 @@ #define AQ_CFG_IS_POLLING_DEF 0U -#define AQ_CFG_FORCE_LEGACY_INT 0U +#define AQ_CFG_FORCE_INTX 0U #define AQ_CFG_INTERRUPT_MODERATION_OFF 0 #define AQ_CFG_INTERRUPT_MODERATION_ON 1 diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c index 414b2e448d59..787ea91802e7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_drvinfo.c @@ -113,19 +113,9 @@ static const struct hwmon_ops aq_hwmon_ops = { .read_string = aq_hwmon_read_string, }; -static u32 aq_hwmon_temp_config[] = { - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, - 0, -}; - -static const struct hwmon_channel_info aq_hwmon_temp = { - .type = hwmon_temp, - .config = aq_hwmon_temp_config, -}; - static const struct hwmon_channel_info * const aq_hwmon_info[] = { - &aq_hwmon_temp, + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index a2606ee3b0a5..6fef47ba0a59 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -15,6 +15,7 @@ #include "aq_macsec.h" #include "aq_main.h" +#include <linux/ethtool.h> #include <linux/linkmode.h> #include <linux/ptp_clock_kernel.h> @@ -266,7 +267,7 @@ static void aq_ethtool_get_strings(struct net_device *ndev, const int rx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_rx_stat_names); const int tx_stat_cnt = ARRAY_SIZE(aq_ethtool_queue_tx_stat_names); char tc_string[8]; - int tc; + unsigned int tc; memset(tc_string, 0, sizeof(tc_string)); memcpy(p, aq_ethtool_stat_names, @@ -275,22 +276,20 @@ static void aq_ethtool_get_strings(struct net_device *ndev, for (tc = 0; tc < cfg->tcs; tc++) { if (cfg->is_qos) - snprintf(tc_string, 8, "TC%d ", tc); + snprintf(tc_string, 8, "TC%u ", tc); for (i = 0; i < cfg->vecs; i++) { for (si = 0; si < rx_stat_cnt; si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_ethtool_queue_rx_stat_names[si], tc_string, AQ_NIC_CFG_TCVEC2RING(cfg, tc, i)); - p += ETH_GSTRING_LEN; } for (si = 0; si < tx_stat_cnt; si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_ethtool_queue_tx_stat_names[si], tc_string, AQ_NIC_CFG_TCVEC2RING(cfg, tc, i)); - p += ETH_GSTRING_LEN; } } } @@ -305,20 +304,18 @@ static void aq_ethtool_get_strings(struct net_device *ndev, for (i = 0; i < max(rx_ring_cnt, tx_ring_cnt); i++) { for (si = 0; si < rx_stat_cnt; si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_ethtool_queue_rx_stat_names[si], tc_string, i ? PTP_HWST_RING_IDX : ptp_ring_idx); - p += ETH_GSTRING_LEN; } if (i >= tx_ring_cnt) continue; for (si = 0; si < tx_stat_cnt; si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_ethtool_queue_tx_stat_names[si], tc_string, i ? PTP_HWST_RING_IDX : ptp_ring_idx); - p += ETH_GSTRING_LEN; } } } @@ -338,9 +335,8 @@ static void aq_ethtool_get_strings(struct net_device *ndev, for (si = 0; si < ARRAY_SIZE(aq_macsec_txsc_stat_names); si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_macsec_txsc_stat_names[si], i); - p += ETH_GSTRING_LEN; } aq_txsc = &nic->macsec_cfg->aq_txsc[i]; for (sa = 0; sa < MACSEC_NUM_AN; sa++) { @@ -349,10 +345,9 @@ static void aq_ethtool_get_strings(struct net_device *ndev, for (si = 0; si < ARRAY_SIZE(aq_macsec_txsa_stat_names); si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_macsec_txsa_stat_names[si], i, sa); - p += ETH_GSTRING_LEN; } } } @@ -369,10 +364,9 @@ static void aq_ethtool_get_strings(struct net_device *ndev, for (si = 0; si < ARRAY_SIZE(aq_macsec_rxsa_stat_names); si++) { - snprintf(p, ETH_GSTRING_LEN, + ethtool_sprintf(&p, aq_macsec_rxsa_stat_names[si], i, sa); - p += ETH_GSTRING_LEN; } } } @@ -652,7 +646,7 @@ static int aq_ethtool_set_wol(struct net_device *ndev, } static int aq_ethtool_get_ts_info(struct net_device *ndev, - struct ethtool_ts_info *info) + struct kernel_ethtool_ts_info *info) { struct aq_nic_s *aq_nic = netdev_priv(ndev); @@ -984,6 +978,76 @@ static int aq_ethtool_set_phy_tunable(struct net_device *ndev, return err; } +static int aq_ethtool_get_module_info(struct net_device *ndev, + struct ethtool_modinfo *modinfo) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + u8 compliance_val, dom_type; + int err; + + /* Module EEPROM is only supported for controllers with external PHY */ + if (aq_nic->aq_nic_cfg.aq_hw_caps->media_type != AQ_HW_MEDIA_TYPE_FIBRE || + !aq_nic->aq_hw_ops->hw_read_module_eeprom) + return -EOPNOTSUPP; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, SFF_8472_COMP_ADDR, 1, &compliance_val); + if (err) + return err; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, SFF_8472_DOM_TYPE_ADDR, 1, &dom_type); + if (err) + return err; + + if (dom_type & SFF_8472_ADDRESS_CHANGE_REQ_MASK || compliance_val == 0x00) { + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + } + return 0; +} + +static int aq_ethtool_get_module_eeprom(struct net_device *ndev, + struct ethtool_eeprom *ee, unsigned char *data) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + unsigned int first, last, len; + int err; + + if (!aq_nic->aq_hw_ops->hw_read_module_eeprom) + return -EOPNOTSUPP; + + first = ee->offset; + last = ee->offset + ee->len; + + if (first < ETH_MODULE_SFF_8079_LEN) { + len = min(last, ETH_MODULE_SFF_8079_LEN); + len -= first; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, first, len, data); + if (err) + return err; + + first += len; + data += len; + } + if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) { + len = min(last, ETH_MODULE_SFF_8472_LEN); + len -= first; + first -= ETH_MODULE_SFF_8079_LEN; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_DIAGNOSTICS_ADDR, first, len, data); + if (err) + return err; + } + return 0; +} + const struct ethtool_ops aq_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -1021,4 +1085,6 @@ const struct ethtool_ops aq_ethtool_ops = { .get_ts_info = aq_ethtool_get_ts_info, .get_phy_tunable = aq_ethtool_get_phy_tunable, .set_phy_tunable = aq_ethtool_set_phy_tunable, + .get_module_info = aq_ethtool_get_module_info, + .get_module_eeprom = aq_ethtool_get_module_eeprom, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h index 6d5be5ebeb13..f26fe1a75539 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h @@ -14,4 +14,12 @@ extern const struct ethtool_ops aq_ethtool_ops; #define AQ_PRIV_FLAGS_MASK (AQ_HW_LOOPBACK_MASK) +#define SFF_8472_ID_ADDR 0x50 +#define SFF_8472_DIAGNOSTICS_ADDR 0x51 + +#define SFF_8472_COMP_ADDR 0x5e +#define SFF_8472_DOM_TYPE_ADDR 0x5c + +#define SFF_8472_ADDRESS_CHANGE_REQ_MASK 0x4 + #endif /* AQ_ETHTOOL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index dbd284660135..42c0efc1b455 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -104,7 +104,7 @@ struct aq_stats_s { }; #define AQ_HW_IRQ_INVALID 0U -#define AQ_HW_IRQ_LEGACY 1U +#define AQ_HW_IRQ_INTX 1U #define AQ_HW_IRQ_MSI 2U #define AQ_HW_IRQ_MSIX 3U @@ -340,6 +340,9 @@ struct aq_hw_ops { int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable); int (*hw_get_mac_temp)(struct aq_hw_s *self, u32 *temp); + + int (*hw_read_module_eeprom)(struct aq_hw_s *self, u8 dev_addr, + u8 reg_start_addr, int len, u8 *data); }; struct aq_fw_ops { diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index 0b2a52199914..b565189e5913 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -123,7 +123,6 @@ static netdev_tx_t aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *nd } #endif - skb_tx_timestamp(skb); return aq_nic_xmit(aq_nic, skb); } @@ -146,7 +145,7 @@ static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu) if (err < 0) goto err_exit; - ndev->mtu = new_mtu; + WRITE_ONCE(ndev->mtu, new_mtu); err_exit: return err; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index d6d6d5d37ff3..e71cd10e4e1f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -127,7 +127,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) cfg->irq_type = aq_pci_func_get_irq_type(self); - if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) || + if ((cfg->irq_type == AQ_HW_IRQ_INTX) || (cfg->aq_hw_caps->vecs == 1U) || (cfg->vecs == 1U)) { cfg->is_rss = 0U; @@ -898,6 +898,8 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb) frags = aq_nic_map_skb(self, skb, ring); + skb_tx_timestamp(skb); + if (likely(frags)) { err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw, ring, frags); @@ -1389,13 +1391,13 @@ int aq_nic_stop(struct aq_nic_s *self) netif_tx_disable(self->ndev); netif_carrier_off(self->ndev); - del_timer_sync(&self->service_timer); + timer_delete_sync(&self->service_timer); cancel_work_sync(&self->service_task); self->aq_hw_ops->hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK); if (self->aq_nic_cfg.is_polling) - del_timer_sync(&self->polling_timer); + timer_delete_sync(&self->polling_timer); else aq_pci_func_free_irqs(self); @@ -1441,7 +1443,9 @@ void aq_nic_deinit(struct aq_nic_s *self, bool link_down) aq_ptp_ring_free(self); aq_ptp_free(self); - if (likely(self->aq_fw_ops->deinit) && link_down) { + /* May be invoked during hot unplug. */ + if (pci_device_is_present(self->pdev) && + likely(self->aq_fw_ops->deinit) && link_down) { mutex_lock(&self->fwreq_mutex); self->aq_fw_ops->deinit(self->aq_hw); mutex_unlock(&self->fwreq_mutex); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index baa5f8cc31f2..08630ee94251 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -162,8 +162,8 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, self->msix_entry_mask |= (1 << i); if (pdev->msix_enabled && affinity_mask) - irq_set_affinity_hint(pci_irq_vector(pdev, i), - affinity_mask); + irq_update_affinity_hint(pci_irq_vector(pdev, i), + affinity_mask); } return err; @@ -187,7 +187,7 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self) continue; if (pdev->msix_enabled) - irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL); + irq_update_affinity_hint(pci_irq_vector(pdev, i), NULL); free_irq(pci_irq_vector(pdev, i), irq_data); self->msix_entry_mask &= ~(1U << i); } @@ -200,7 +200,7 @@ unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self) if (self->pdev->msi_enabled) return AQ_HW_IRQ_MSI; - return AQ_HW_IRQ_LEGACY; + return AQ_HW_IRQ_INTX; } static void aq_pci_free_irq_vectors(struct aq_nic_s *self) @@ -298,11 +298,8 @@ static int aq_pci_probe(struct pci_dev *pdev, numvecs += AQ_HW_SERVICE_IRQS; /*enable interrupts */ -#if !AQ_CFG_FORCE_LEGACY_INT - err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, - PCI_IRQ_MSIX | PCI_IRQ_MSI | - PCI_IRQ_LEGACY); - +#if !AQ_CFG_FORCE_INTX + err = pci_alloc_irq_vectors(self->pdev, 1, numvecs, PCI_IRQ_ALL_TYPES); if (err < 0) goto err_hwinit; numvecs = err; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index f7433abd6591..f21de0c21e52 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -557,7 +557,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi, } frag_cnt++; - next_ = buff_->next, + next_ = buff_->next; buff_ = &self->buff_ring[next_]; is_rsc_completed = aq_ring_dx_in_range(self->sw_head, @@ -583,7 +583,7 @@ static int __aq_ring_rx_clean(struct aq_ring_s *self, struct napi_struct *napi, err = -EIO; goto err_exit; } - next_ = buff_->next, + next_ = buff_->next; buff_ = &self->buff_ring[next_]; buff_->is_cleaned = true; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 9dfd68f0fda9..8de2cdd09213 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -352,7 +352,7 @@ static int hw_atl_a0_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 54e70f07b573..493432d036b9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -562,7 +562,7 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; @@ -1654,6 +1654,137 @@ static int hw_atl_b0_get_mac_temp(struct aq_hw_s *self, u32 *temp) return 0; } +#define START_TRANSMIT 0x5001 +#define START_READ_TRANSMIT 0x5101 +#define STOP_TRANSMIT 0x3001 +#define REPEAT_TRANSMIT 0x1001 +#define REPEAT_NACK_TRANSMIT 0x1011 + +static int hw_atl_b0_smb0_wait_result(struct aq_hw_s *self, bool expect_ack) +{ + int err; + u32 val; + + err = readx_poll_timeout(hw_atl_smb0_byte_transfer_complete_get, + self, val, val == 1, 100U, 10000U); + if (err) + return err; + if (hw_atl_smb0_receive_acknowledged_get(self) != expect_ack) + return -EIO; + return 0; +} + +/* Starts an I2C/SMBUS write to a given address. addr is in 7-bit format, + * the read/write bit is not part of it. + */ +static int hw_atl_b0_smb0_start_write(struct aq_hw_s *self, u32 addr) +{ + hw_atl_smb0_tx_data_set(self, (addr << 1) | 0); + hw_atl_smb0_provisioning2_set(self, START_TRANSMIT); + return hw_atl_b0_smb0_wait_result(self, 0); +} + +/* Writes a single byte as part of an ongoing write started by start_write. */ +static int hw_atl_b0_smb0_write_byte(struct aq_hw_s *self, u32 data) +{ + hw_atl_smb0_tx_data_set(self, data); + hw_atl_smb0_provisioning2_set(self, REPEAT_TRANSMIT); + return hw_atl_b0_smb0_wait_result(self, 0); +} + +/* Starts an I2C/SMBUS read to a given address. addr is in 7-bit format, + * the read/write bit is not part of it. + */ +static int hw_atl_b0_smb0_start_read(struct aq_hw_s *self, u32 addr) +{ + int err; + + hw_atl_smb0_tx_data_set(self, (addr << 1) | 1); + hw_atl_smb0_provisioning2_set(self, START_READ_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 0); + if (err) + return err; + if (hw_atl_smb0_repeated_start_detect_get(self) == 0) + return -EIO; + return 0; +} + +/* Reads a single byte as part of an ongoing read started by start_read. */ +static int hw_atl_b0_smb0_read_byte(struct aq_hw_s *self) +{ + int err; + + hw_atl_smb0_provisioning2_set(self, REPEAT_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 0); + if (err) + return err; + return hw_atl_smb0_rx_data_get(self); +} + +/* Reads the last byte of an ongoing read. */ +static int hw_atl_b0_smb0_read_byte_nack(struct aq_hw_s *self) +{ + int err; + + hw_atl_smb0_provisioning2_set(self, REPEAT_NACK_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 1); + if (err) + return err; + return hw_atl_smb0_rx_data_get(self); +} + +/* Sends a stop condition and ends a transfer. */ +static void hw_atl_b0_smb0_stop(struct aq_hw_s *self) +{ + hw_atl_smb0_provisioning2_set(self, STOP_TRANSMIT); +} + +static int hw_atl_b0_read_module_eeprom(struct aq_hw_s *self, u8 dev_addr, + u8 reg_start_addr, int len, u8 *data) +{ + int i, b; + int err; + u32 val; + + /* Wait for SMBUS0 to be idle */ + err = readx_poll_timeout(hw_atl_smb0_bus_busy_get, self, + val, val == 0, 100U, 10000U); + if (err) + return err; + + err = hw_atl_b0_smb0_start_write(self, dev_addr); + if (err) + goto out; + + err = hw_atl_b0_smb0_write_byte(self, reg_start_addr); + if (err) + goto out; + + err = hw_atl_b0_smb0_start_read(self, dev_addr); + if (err) + goto out; + + for (i = 0; i < len - 1; i++) { + b = hw_atl_b0_smb0_read_byte(self); + if (b < 0) { + err = b; + goto out; + } + data[i] = (u8)b; + } + + b = hw_atl_b0_smb0_read_byte_nack(self); + if (b < 0) { + err = b; + goto out; + } + data[i] = (u8)b; + +out: + hw_atl_b0_smb0_stop(self); + return err; +} + const struct aq_hw_ops hw_atl_ops_b0 = { .hw_soft_reset = hw_atl_utils_soft_reset, .hw_prepare = hw_atl_utils_initfw, @@ -1712,4 +1843,5 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_set_fc = hw_atl_b0_set_fc, .hw_get_mac_temp = hw_atl_b0_get_mac_temp, + .hw_read_module_eeprom = hw_atl_b0_read_module_eeprom, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 7b67bdd8a258..d07af1271d59 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -57,6 +57,49 @@ u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw) HW_ATL_TS_DATA_OUT_SHIFT); } +u32 hw_atl_smb0_bus_busy_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_BUS_BUSY_ADR, + HW_ATL_SMB0_BUS_BUSY_MSK, + HW_ATL_SMB0_BUS_BUSY_SHIFT); +} + +u32 hw_atl_smb0_byte_transfer_complete_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_ADR, + HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_MSK, + HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_SHIFT); +} + +u32 hw_atl_smb0_receive_acknowledged_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_RX_ACKNOWLEDGED_ADR, + HW_ATL_SMB0_RX_ACKNOWLEDGED_MSK, + HW_ATL_SMB0_RX_ACKNOWLEDGED_SHIFT); +} + +u32 hw_atl_smb0_repeated_start_detect_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_REPEATED_START_DETECT_ADR, + HW_ATL_SMB0_REPEATED_START_DETECT_MSK, + HW_ATL_SMB0_REPEATED_START_DETECT_SHIFT); +} + +u32 hw_atl_smb0_rx_data_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_SMB0_RECEIVED_DATA_ADR); +} + +void hw_atl_smb0_tx_data_set(struct aq_hw_s *aq_hw, u32 data) +{ + return aq_hw_write_reg(aq_hw, HW_ATL_SMB0_TRANSMITTED_DATA_ADR, data); +} + +void hw_atl_smb0_provisioning2_set(struct aq_hw_s *aq_hw, u32 data) +{ + return aq_hw_write_reg(aq_hw, HW_ATL_SMB0_PROVISIONING2_ADR, data); +} + /* global */ void hw_atl_reg_glb_cpu_sem_set(struct aq_hw_s *aq_hw, u32 glb_cpu_sem, u32 semaphore) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 58f5ee0a6214..5fd506acacb5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -34,6 +34,27 @@ u32 hw_atl_ts_ready_latch_high_get(struct aq_hw_s *aq_hw); /* get temperature sense data */ u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw); +/* SMBUS0 bus busy */ +u32 hw_atl_smb0_bus_busy_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 byte transfer complete */ +u32 hw_atl_smb0_byte_transfer_complete_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 receive acknowledged */ +u32 hw_atl_smb0_receive_acknowledged_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 set transmitted data (only leftmost byte of data valid) */ +void hw_atl_smb0_tx_data_set(struct aq_hw_s *aq_hw, u32 data); + +/* SMBUS0 provisioning2 command register */ +void hw_atl_smb0_provisioning2_set(struct aq_hw_s *aq_hw, u32 data); + +/* SMBUS0 repeated start detect */ +u32 hw_atl_smb0_repeated_start_detect_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 received data register */ +u32 hw_atl_smb0_rx_data_get(struct aq_hw_s *aq_hw); + /* global */ /* set global microprocessor semaphore */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 4a6467031b9e..fce30d90b6cb 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -42,6 +42,38 @@ #define HW_ATL_TS_DATA_OUT_SHIFT 0 #define HW_ATL_TS_DATA_OUT_WIDTH 12 +/* SMBUS0 Received Data register */ +#define HW_ATL_SMB0_RECEIVED_DATA_ADR 0x00000748 +/* SMBUS0 Transmitted Data register */ +#define HW_ATL_SMB0_TRANSMITTED_DATA_ADR 0x00000608 + +/* SMBUS0 Global Provisioning 2 register */ +#define HW_ATL_SMB0_PROVISIONING2_ADR 0x00000604 + +/* SMBUS0 Bus Busy Bitfield Definitions */ +#define HW_ATL_SMB0_BUS_BUSY_ADR 0x00000744 +#define HW_ATL_SMB0_BUS_BUSY_MSK 0x00000080 +#define HW_ATL_SMB0_BUS_BUSY_SHIFT 7 +#define HW_ATL_SMB0_BUS_BUSY_WIDTH 1 + +/* SMBUS0 Byte Transfer Complete Bitfield Definitions */ +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_ADR 0x00000744 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_MSK 0x00000002 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_SHIFT 1 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_WIDTH 1 + +/* SMBUS0 Receive Acknowledge Bitfield Definitions */ +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_ADR 0x00000744 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_MSK 0x00000100 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_SHIFT 8 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_WIDTH 1 + +/* SMBUS0 Repeated Start Detect Bitfield Definitions */ +#define HW_ATL_SMB0_REPEATED_START_DETECT_ADR 0x00000744 +#define HW_ATL_SMB0_REPEATED_START_DETECT_MSK 0x00000004 +#define HW_ATL_SMB0_REPEATED_START_DETECT_SHIFT 2 +#define HW_ATL_SMB0_REPEATED_START_DETECT_WIDTH 1 + /* global microprocessor semaphore definitions * base address: 0x000003a0 * parameter: semaphore {s} | stride size 0x4 | range [0, 15] diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index f5901f8e3907..f6b990b7f5b4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -226,7 +226,6 @@ struct __packed offload_info { struct offload_port_info ports; struct offload_ka_info kas; struct offload_rr_info rrs; - u8 buf[]; }; struct __packed hw_atl_utils_fw_rpc { diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c index 220400a633f5..b0ed572e88c6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c @@ -534,7 +534,7 @@ static int hw_atl2_hw_init(struct aq_hw_s *self, const u8 *mac_addr) { static u32 aq_hw_atl2_igcr_table_[4][2] = { [AQ_HW_IRQ_INVALID] = { 0x20000000U, 0x20000000U }, - [AQ_HW_IRQ_LEGACY] = { 0x20000080U, 0x20000080U }, + [AQ_HW_IRQ_INTX] = { 0x20000080U, 0x20000080U }, [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; |