Commit 9b894cdd authored by David S. Miller's avatar David S. Miller

Merge branch 'aquantia-fixes'

Igor Russkikh says:

====================
Aquantia atlantic hot fixes 03-2018

This is a set of atlantic driver hot fixes for various areas:

Some issues with hardware reset covered,
Fixed napi_poll flood happening on some traffic conditions,
Allow system to change MAC address on live device,
Add pci shutdown handler.

patch v2:
- reverse christmas tree
- remove driver private parameter, replacing it with define.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1959031e c89bf1cd
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#define AQ_CFG_TX_FRAME_MAX (16U * 1024U) #define AQ_CFG_TX_FRAME_MAX (16U * 1024U)
#define AQ_CFG_RX_FRAME_MAX (4U * 1024U) #define AQ_CFG_RX_FRAME_MAX (4U * 1024U)
#define AQ_CFG_TX_CLEAN_BUDGET 256U
/* LRO */ /* LRO */
#define AQ_CFG_IS_LRO_DEF 1U #define AQ_CFG_IS_LRO_DEF 1U
......
...@@ -247,6 +247,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self) ...@@ -247,6 +247,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self)
self->ndev->hw_features |= aq_hw_caps->hw_features; self->ndev->hw_features |= aq_hw_caps->hw_features;
self->ndev->features = aq_hw_caps->hw_features; self->ndev->features = aq_hw_caps->hw_features;
self->ndev->priv_flags = aq_hw_caps->hw_priv_flags; self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN; self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN;
self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN; self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN;
...@@ -937,3 +939,23 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg) ...@@ -937,3 +939,23 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg)
out: out:
return err; return err;
} }
void aq_nic_shutdown(struct aq_nic_s *self)
{
int err = 0;
if (!self->ndev)
return;
rtnl_lock();
netif_device_detach(self->ndev);
err = aq_nic_stop(self);
if (err < 0)
goto err_exit;
aq_nic_deinit(self);
err_exit:
rtnl_unlock();
}
\ No newline at end of file
...@@ -118,5 +118,6 @@ struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); ...@@ -118,5 +118,6 @@ struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
u32 aq_nic_get_fw_version(struct aq_nic_s *self); u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
void aq_nic_shutdown(struct aq_nic_s *self);
#endif /* AQ_NIC_H */ #endif /* AQ_NIC_H */
...@@ -323,6 +323,20 @@ static void aq_pci_remove(struct pci_dev *pdev) ...@@ -323,6 +323,20 @@ static void aq_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static void aq_pci_shutdown(struct pci_dev *pdev)
{
struct aq_nic_s *self = pci_get_drvdata(pdev);
aq_nic_shutdown(self);
pci_disable_device(pdev);
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}
}
static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg) static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg)
{ {
struct aq_nic_s *self = pci_get_drvdata(pdev); struct aq_nic_s *self = pci_get_drvdata(pdev);
...@@ -345,6 +359,7 @@ static struct pci_driver aq_pci_ops = { ...@@ -345,6 +359,7 @@ static struct pci_driver aq_pci_ops = {
.remove = aq_pci_remove, .remove = aq_pci_remove,
.suspend = aq_pci_suspend, .suspend = aq_pci_suspend,
.resume = aq_pci_resume, .resume = aq_pci_resume,
.shutdown = aq_pci_shutdown,
}; };
module_pci_driver(aq_pci_ops); module_pci_driver(aq_pci_ops);
...@@ -136,11 +136,12 @@ void aq_ring_queue_stop(struct aq_ring_s *ring) ...@@ -136,11 +136,12 @@ void aq_ring_queue_stop(struct aq_ring_s *ring)
netif_stop_subqueue(ndev, ring->idx); netif_stop_subqueue(ndev, ring->idx);
} }
void aq_ring_tx_clean(struct aq_ring_s *self) bool aq_ring_tx_clean(struct aq_ring_s *self)
{ {
struct device *dev = aq_nic_get_dev(self->aq_nic); struct device *dev = aq_nic_get_dev(self->aq_nic);
unsigned int budget = AQ_CFG_TX_CLEAN_BUDGET;
for (; self->sw_head != self->hw_head; for (; self->sw_head != self->hw_head && budget--;
self->sw_head = aq_ring_next_dx(self, self->sw_head)) { self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
...@@ -167,6 +168,8 @@ void aq_ring_tx_clean(struct aq_ring_s *self) ...@@ -167,6 +168,8 @@ void aq_ring_tx_clean(struct aq_ring_s *self)
buff->pa = 0U; buff->pa = 0U;
buff->eop_index = 0xffffU; buff->eop_index = 0xffffU;
} }
return !!budget;
} }
#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) #define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
......
...@@ -153,7 +153,7 @@ void aq_ring_free(struct aq_ring_s *self); ...@@ -153,7 +153,7 @@ void aq_ring_free(struct aq_ring_s *self);
void aq_ring_update_queue_state(struct aq_ring_s *ring); void aq_ring_update_queue_state(struct aq_ring_s *ring);
void aq_ring_queue_wake(struct aq_ring_s *ring); void aq_ring_queue_wake(struct aq_ring_s *ring);
void aq_ring_queue_stop(struct aq_ring_s *ring); void aq_ring_queue_stop(struct aq_ring_s *ring);
void aq_ring_tx_clean(struct aq_ring_s *self); bool aq_ring_tx_clean(struct aq_ring_s *self);
int aq_ring_rx_clean(struct aq_ring_s *self, int aq_ring_rx_clean(struct aq_ring_s *self,
struct napi_struct *napi, struct napi_struct *napi,
int *work_done, int *work_done,
......
...@@ -35,12 +35,12 @@ struct aq_vec_s { ...@@ -35,12 +35,12 @@ struct aq_vec_s {
static int aq_vec_poll(struct napi_struct *napi, int budget) static int aq_vec_poll(struct napi_struct *napi, int budget)
{ {
struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi); struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
unsigned int sw_tail_old = 0U;
struct aq_ring_s *ring = NULL; struct aq_ring_s *ring = NULL;
bool was_tx_cleaned = true;
unsigned int i = 0U;
int work_done = 0; int work_done = 0;
int err = 0; int err = 0;
unsigned int i = 0U;
unsigned int sw_tail_old = 0U;
bool was_tx_cleaned = false;
if (!self) { if (!self) {
err = -EINVAL; err = -EINVAL;
...@@ -57,9 +57,8 @@ static int aq_vec_poll(struct napi_struct *napi, int budget) ...@@ -57,9 +57,8 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
if (ring[AQ_VEC_TX_ID].sw_head != if (ring[AQ_VEC_TX_ID].sw_head !=
ring[AQ_VEC_TX_ID].hw_head) { ring[AQ_VEC_TX_ID].hw_head) {
aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]); aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]);
was_tx_cleaned = true;
} }
err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw, err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
...@@ -90,7 +89,7 @@ static int aq_vec_poll(struct napi_struct *napi, int budget) ...@@ -90,7 +89,7 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
} }
} }
if (was_tx_cleaned) if (!was_tx_cleaned)
work_done = budget; work_done = budget;
if (work_done < budget) { if (work_done < budget) {
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
#define HW_ATL_UCP_0X370_REG 0x0370U #define HW_ATL_UCP_0X370_REG 0x0370U
#define HW_ATL_MIF_CMD 0x0200U
#define HW_ATL_MIF_ADDR 0x0208U
#define HW_ATL_MIF_VAL 0x020CU
#define HW_ATL_FW_SM_RAM 0x2U #define HW_ATL_FW_SM_RAM 0x2U
#define HW_ATL_MPI_FW_VERSION 0x18 #define HW_ATL_MPI_FW_VERSION 0x18
#define HW_ATL_MPI_CONTROL_ADR 0x0368U #define HW_ATL_MPI_CONTROL_ADR 0x0368U
...@@ -79,16 +83,15 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) ...@@ -79,16 +83,15 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
{ {
u32 gsr, val;
int k = 0; int k = 0;
u32 gsr;
aq_hw_write_reg(self, 0x404, 0x40e1); aq_hw_write_reg(self, 0x404, 0x40e1);
AQ_HW_SLEEP(50); AQ_HW_SLEEP(50);
/* Cleanup SPI */ /* Cleanup SPI */
aq_hw_write_reg(self, 0x534, 0xA0); val = aq_hw_read_reg(self, 0x53C);
aq_hw_write_reg(self, 0x100, 0x9F); aq_hw_write_reg(self, 0x53C, val | 0x10);
aq_hw_write_reg(self, 0x100, 0x809F);
gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR); gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000); aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
...@@ -97,7 +100,14 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) ...@@ -97,7 +100,14 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
aq_hw_write_reg(self, 0x404, 0x80e0); aq_hw_write_reg(self, 0x404, 0x80e0);
aq_hw_write_reg(self, 0x32a8, 0x0); aq_hw_write_reg(self, 0x32a8, 0x0);
aq_hw_write_reg(self, 0x520, 0x1); aq_hw_write_reg(self, 0x520, 0x1);
/* Reset SPI again because of possible interrupted SPI burst */
val = aq_hw_read_reg(self, 0x53C);
aq_hw_write_reg(self, 0x53C, val | 0x10);
AQ_HW_SLEEP(10); AQ_HW_SLEEP(10);
/* Clear SPI reset state */
aq_hw_write_reg(self, 0x53C, val & ~0x10);
aq_hw_write_reg(self, 0x404, 0x180e0); aq_hw_write_reg(self, 0x404, 0x180e0);
for (k = 0; k < 1000; k++) { for (k = 0; k < 1000; k++) {
...@@ -141,13 +151,15 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self) ...@@ -141,13 +151,15 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
aq_pr_err("FW kickstart failed\n"); aq_pr_err("FW kickstart failed\n");
return -EIO; return -EIO;
} }
/* Old FW requires fixed delay after init */
AQ_HW_SLEEP(15);
return 0; return 0;
} }
static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
{ {
u32 gsr, rbl_status; u32 gsr, val, rbl_status;
int k; int k;
aq_hw_write_reg(self, 0x404, 0x40e1); aq_hw_write_reg(self, 0x404, 0x40e1);
...@@ -157,6 +169,10 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) ...@@ -157,6 +169,10 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
/* Alter RBL status */ /* Alter RBL status */
aq_hw_write_reg(self, 0x388, 0xDEAD); aq_hw_write_reg(self, 0x388, 0xDEAD);
/* Cleanup SPI */
val = aq_hw_read_reg(self, 0x53C);
aq_hw_write_reg(self, 0x53C, val | 0x10);
/* Global software reset*/ /* Global software reset*/
hw_atl_rx_rx_reg_res_dis_set(self, 0U); hw_atl_rx_rx_reg_res_dis_set(self, 0U);
hw_atl_tx_tx_reg_res_dis_set(self, 0U); hw_atl_tx_tx_reg_res_dis_set(self, 0U);
...@@ -204,6 +220,8 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) ...@@ -204,6 +220,8 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
aq_pr_err("FW kickstart failed\n"); aq_pr_err("FW kickstart failed\n");
return -EIO; return -EIO;
} }
/* Old FW requires fixed delay after init */
AQ_HW_SLEEP(15);
return 0; return 0;
} }
...@@ -255,18 +273,22 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, ...@@ -255,18 +273,22 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
} }
} }
aq_hw_write_reg(self, 0x00000208U, a); aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
for (++cnt; --cnt;) {
u32 i = 0U;
aq_hw_write_reg(self, 0x00000200U, 0x00008000U); for (++cnt; --cnt && !err;) {
aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
for (i = 1024U; if (IS_CHIP_FEATURE(REVISION_B1))
(0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) { AQ_HW_WAIT_FOR(a != aq_hw_read_reg(self,
} HW_ATL_MIF_ADDR),
1, 1000U);
else
AQ_HW_WAIT_FOR(!(0x100 & aq_hw_read_reg(self,
HW_ATL_MIF_CMD)),
1, 1000U);
*(p++) = aq_hw_read_reg(self, 0x0000020CU); *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
a += 4;
} }
hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
...@@ -662,14 +684,18 @@ void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) ...@@ -662,14 +684,18 @@ void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
u32 val = hw_atl_reg_glb_mif_id_get(self); u32 val = hw_atl_reg_glb_mif_id_get(self);
u32 mif_rev = val & 0xFFU; u32 mif_rev = val & 0xFFU;
if ((3U & mif_rev) == 1U) { if ((0xFU & mif_rev) == 1U) {
chip_features |= chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
HAL_ATLANTIC_UTILS_CHIP_MPI_AQ | HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
HAL_ATLANTIC_UTILS_CHIP_MIPS; HAL_ATLANTIC_UTILS_CHIP_MIPS;
} else if ((3U & mif_rev) == 2U) { } else if ((0xFU & mif_rev) == 2U) {
chip_features |= chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 | HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
HAL_ATLANTIC_UTILS_CHIP_MIPS |
HAL_ATLANTIC_UTILS_CHIP_TPO2 |
HAL_ATLANTIC_UTILS_CHIP_RPF2;
} else if ((0xFU & mif_rev) == 0xAU) {
chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 |
HAL_ATLANTIC_UTILS_CHIP_MPI_AQ | HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
HAL_ATLANTIC_UTILS_CHIP_MIPS | HAL_ATLANTIC_UTILS_CHIP_MIPS |
HAL_ATLANTIC_UTILS_CHIP_TPO2 | HAL_ATLANTIC_UTILS_CHIP_TPO2 |
......
...@@ -161,6 +161,7 @@ struct __packed hw_aq_atl_utils_mbox { ...@@ -161,6 +161,7 @@ struct __packed hw_aq_atl_utils_mbox {
#define HAL_ATLANTIC_UTILS_CHIP_MPI_AQ 0x00000010U #define HAL_ATLANTIC_UTILS_CHIP_MPI_AQ 0x00000010U
#define HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 0x01000000U #define HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 0x01000000U
#define HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 0x02000000U #define HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 0x02000000U
#define HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 0x04000000U
#define IS_CHIP_FEATURE(_F_) (HAL_ATLANTIC_UTILS_CHIP_##_F_ & \ #define IS_CHIP_FEATURE(_F_) (HAL_ATLANTIC_UTILS_CHIP_##_F_ & \
self->chip_features) self->chip_features)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#define NIC_MAJOR_DRIVER_VERSION 2 #define NIC_MAJOR_DRIVER_VERSION 2
#define NIC_MINOR_DRIVER_VERSION 0 #define NIC_MINOR_DRIVER_VERSION 0
#define NIC_BUILD_DRIVER_VERSION 2 #define NIC_BUILD_DRIVER_VERSION 2
#define NIC_REVISION_DRIVER_VERSION 0 #define NIC_REVISION_DRIVER_VERSION 1
#define AQ_CFG_DRV_VERSION_SUFFIX "-kern" #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment