Commit 49328939 authored by David S. Miller's avatar David S. Miller

Merge branch 'ionic-locking-and-filter-fixes'

Shannon Nelson says:

====================
ionic: locking and filter fixes

These patches address an ethtool show regs problem, some locking sightings,
and issues with RSS hash and filter_id tracking after a managed FW update.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5d93518e 0925e9db
...@@ -103,15 +103,18 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs, ...@@ -103,15 +103,18 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
void *p) void *p)
{ {
struct ionic_lif *lif = netdev_priv(netdev); struct ionic_lif *lif = netdev_priv(netdev);
unsigned int offset;
unsigned int size; unsigned int size;
regs->version = IONIC_DEV_CMD_REG_VERSION; regs->version = IONIC_DEV_CMD_REG_VERSION;
offset = 0;
size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32); size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
memcpy_fromio(p, lif->ionic->idev.dev_info_regs->words, size); memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
offset += size;
size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32); size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
memcpy_fromio(p, lif->ionic->idev.dev_cmd_regs->words, size); memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
} }
static int ionic_get_link_ksettings(struct net_device *netdev, static int ionic_get_link_ksettings(struct net_device *netdev,
......
...@@ -96,8 +96,7 @@ static void ionic_link_status_check(struct ionic_lif *lif) ...@@ -96,8 +96,7 @@ static void ionic_link_status_check(struct ionic_lif *lif)
u16 link_status; u16 link_status;
bool link_up; bool link_up;
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state) || if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
test_bit(IONIC_LIF_F_QUEUE_RESET, lif->state))
return; return;
link_status = le16_to_cpu(lif->info->status.link_status); link_status = le16_to_cpu(lif->info->status.link_status);
...@@ -114,16 +113,22 @@ static void ionic_link_status_check(struct ionic_lif *lif) ...@@ -114,16 +113,22 @@ static void ionic_link_status_check(struct ionic_lif *lif)
netif_carrier_on(netdev); netif_carrier_on(netdev);
} }
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
mutex_lock(&lif->queue_lock);
ionic_start_queues(lif); ionic_start_queues(lif);
mutex_unlock(&lif->queue_lock);
}
} else { } else {
if (netif_carrier_ok(netdev)) { if (netif_carrier_ok(netdev)) {
netdev_info(netdev, "Link down\n"); netdev_info(netdev, "Link down\n");
netif_carrier_off(netdev); netif_carrier_off(netdev);
} }
if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) if (lif->netdev->flags & IFF_UP && netif_running(lif->netdev)) {
mutex_lock(&lif->queue_lock);
ionic_stop_queues(lif); ionic_stop_queues(lif);
mutex_unlock(&lif->queue_lock);
}
} }
clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state); clear_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state);
...@@ -863,8 +868,7 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr) ...@@ -863,8 +868,7 @@ static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr)
if (f) if (f)
return 0; return 0;
netdev_dbg(lif->netdev, "rx_filter add ADDR %pM (id %d)\n", addr, netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
ctx.comp.rx_filter_add.filter_id);
memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN); memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
...@@ -893,6 +897,9 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr) ...@@ -893,6 +897,9 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
return -ENOENT; return -ENOENT;
} }
netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n",
addr, f->filter_id);
ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id); ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
ionic_rx_filter_free(lif, f); ionic_rx_filter_free(lif, f);
spin_unlock_bh(&lif->rx_filters.lock); spin_unlock_bh(&lif->rx_filters.lock);
...@@ -901,9 +908,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr) ...@@ -901,9 +908,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
if (err && err != -EEXIST) if (err && err != -EEXIST)
return err; return err;
netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr,
ctx.cmd.rx_filter_del.filter_id);
return 0; return 0;
} }
...@@ -1351,13 +1355,11 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, ...@@ -1351,13 +1355,11 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
}; };
int err; int err;
netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid);
err = ionic_adminq_post_wait(lif, &ctx); err = ionic_adminq_post_wait(lif, &ctx);
if (err) if (err)
return err; return err;
netdev_dbg(netdev, "rx_filter add VLAN %d (id %d)\n", vid,
ctx.comp.rx_filter_add.filter_id);
return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx); return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
} }
...@@ -1382,8 +1384,8 @@ static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, ...@@ -1382,8 +1384,8 @@ static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
return -ENOENT; return -ENOENT;
} }
netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n", vid, netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n",
le32_to_cpu(ctx.cmd.rx_filter_del.filter_id)); vid, f->filter_id);
ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id); ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
ionic_rx_filter_free(lif, f); ionic_rx_filter_free(lif, f);
...@@ -1993,16 +1995,13 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg) ...@@ -1993,16 +1995,13 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
bool running; bool running;
int err = 0; int err = 0;
err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET); mutex_lock(&lif->queue_lock);
if (err)
return err;
running = netif_running(lif->netdev); running = netif_running(lif->netdev);
if (running) { if (running) {
netif_device_detach(lif->netdev); netif_device_detach(lif->netdev);
err = ionic_stop(lif->netdev); err = ionic_stop(lif->netdev);
if (err) if (err)
goto reset_out; return err;
} }
if (cb) if (cb)
...@@ -2012,9 +2011,7 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg) ...@@ -2012,9 +2011,7 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
err = ionic_open(lif->netdev); err = ionic_open(lif->netdev);
netif_device_attach(lif->netdev); netif_device_attach(lif->netdev);
} }
mutex_unlock(&lif->queue_lock);
reset_out:
clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state);
return err; return err;
} }
...@@ -2161,7 +2158,9 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif) ...@@ -2161,7 +2158,9 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
if (test_bit(IONIC_LIF_F_UP, lif->state)) { if (test_bit(IONIC_LIF_F_UP, lif->state)) {
dev_info(ionic->dev, "Surprise FW stop, stopping queues\n"); dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
mutex_lock(&lif->queue_lock);
ionic_stop_queues(lif); ionic_stop_queues(lif);
mutex_unlock(&lif->queue_lock);
} }
if (netif_running(lif->netdev)) { if (netif_running(lif->netdev)) {
...@@ -2280,15 +2279,15 @@ static void ionic_lif_deinit(struct ionic_lif *lif) ...@@ -2280,15 +2279,15 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
cancel_work_sync(&lif->deferred.work); cancel_work_sync(&lif->deferred.work);
cancel_work_sync(&lif->tx_timeout_work); cancel_work_sync(&lif->tx_timeout_work);
ionic_rx_filters_deinit(lif); ionic_rx_filters_deinit(lif);
}
if (lif->netdev->features & NETIF_F_RXHASH) if (lif->netdev->features & NETIF_F_RXHASH)
ionic_lif_rss_deinit(lif); ionic_lif_rss_deinit(lif);
}
napi_disable(&lif->adminqcq->napi); napi_disable(&lif->adminqcq->napi);
ionic_lif_qcq_deinit(lif, lif->notifyqcq); ionic_lif_qcq_deinit(lif, lif->notifyqcq);
ionic_lif_qcq_deinit(lif, lif->adminqcq); ionic_lif_qcq_deinit(lif, lif->adminqcq);
mutex_destroy(&lif->queue_lock);
ionic_lif_reset(lif); ionic_lif_reset(lif);
} }
...@@ -2465,6 +2464,7 @@ static int ionic_lif_init(struct ionic_lif *lif) ...@@ -2465,6 +2464,7 @@ static int ionic_lif_init(struct ionic_lif *lif)
return err; return err;
lif->hw_index = le16_to_cpu(comp.hw_index); lif->hw_index = le16_to_cpu(comp.hw_index);
mutex_init(&lif->queue_lock);
/* now that we have the hw_index we can figure out our doorbell page */ /* now that we have the hw_index we can figure out our doorbell page */
lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif); lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
......
...@@ -135,7 +135,6 @@ enum ionic_lif_state_flags { ...@@ -135,7 +135,6 @@ enum ionic_lif_state_flags {
IONIC_LIF_F_SW_DEBUG_STATS, IONIC_LIF_F_SW_DEBUG_STATS,
IONIC_LIF_F_UP, IONIC_LIF_F_UP,
IONIC_LIF_F_LINK_CHECK_REQUESTED, IONIC_LIF_F_LINK_CHECK_REQUESTED,
IONIC_LIF_F_QUEUE_RESET,
IONIC_LIF_F_FW_RESET, IONIC_LIF_F_FW_RESET,
/* leave this as last */ /* leave this as last */
...@@ -165,6 +164,7 @@ struct ionic_lif { ...@@ -165,6 +164,7 @@ struct ionic_lif {
unsigned int hw_index; unsigned int hw_index;
unsigned int kern_pid; unsigned int kern_pid;
u64 __iomem *kern_dbpage; u64 __iomem *kern_dbpage;
struct mutex queue_lock; /* lock for queue structures */
spinlock_t adminq_lock; /* lock for AdminQ operations */ spinlock_t adminq_lock; /* lock for AdminQ operations */
struct ionic_qcq *adminqcq; struct ionic_qcq *adminqcq;
struct ionic_qcq *notifyqcq; struct ionic_qcq *notifyqcq;
...@@ -213,12 +213,6 @@ struct ionic_lif { ...@@ -213,12 +213,6 @@ struct ionic_lif {
#define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q) #define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q)
#define lif_to_rxq(lif, i) (&lif_to_txqcq((lif), i)->q) #define lif_to_rxq(lif, i) (&lif_to_txqcq((lif), i)->q)
/* return 0 if successfully set the bit, else non-zero */
static inline int ionic_wait_for_bit(struct ionic_lif *lif, int bitname)
{
return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE);
}
static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs) static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)
{ {
u32 mult = le32_to_cpu(ionic->ident.dev.intr_coal_mult); u32 mult = le32_to_cpu(ionic->ident.dev.intr_coal_mult);
......
...@@ -21,13 +21,16 @@ void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f) ...@@ -21,13 +21,16 @@ void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f)
void ionic_rx_filter_replay(struct ionic_lif *lif) void ionic_rx_filter_replay(struct ionic_lif *lif)
{ {
struct ionic_rx_filter_add_cmd *ac; struct ionic_rx_filter_add_cmd *ac;
struct hlist_head new_id_list;
struct ionic_admin_ctx ctx; struct ionic_admin_ctx ctx;
struct ionic_rx_filter *f; struct ionic_rx_filter *f;
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *tmp; struct hlist_node *tmp;
unsigned int key;
unsigned int i; unsigned int i;
int err; int err;
INIT_HLIST_HEAD(&new_id_list);
ac = &ctx.cmd.rx_filter_add; ac = &ctx.cmd.rx_filter_add;
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
...@@ -58,9 +61,30 @@ void ionic_rx_filter_replay(struct ionic_lif *lif) ...@@ -58,9 +61,30 @@ void ionic_rx_filter_replay(struct ionic_lif *lif)
ac->mac.addr); ac->mac.addr);
break; break;
} }
spin_lock_bh(&lif->rx_filters.lock);
ionic_rx_filter_free(lif, f);
spin_unlock_bh(&lif->rx_filters.lock);
continue;
} }
/* remove from old id list, save new id in tmp list */
spin_lock_bh(&lif->rx_filters.lock);
hlist_del(&f->by_id);
spin_unlock_bh(&lif->rx_filters.lock);
f->filter_id = le32_to_cpu(ctx.comp.rx_filter_add.filter_id);
hlist_add_head(&f->by_id, &new_id_list);
} }
} }
/* rebuild the by_id hash lists with the new filter ids */
spin_lock_bh(&lif->rx_filters.lock);
hlist_for_each_entry_safe(f, tmp, &new_id_list, by_id) {
key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK;
head = &lif->rx_filters.by_id[key];
hlist_add_head(&f->by_id, head);
}
spin_unlock_bh(&lif->rx_filters.lock);
} }
int ionic_rx_filters_init(struct ionic_lif *lif) int ionic_rx_filters_init(struct ionic_lif *lif)
...@@ -69,10 +93,12 @@ int ionic_rx_filters_init(struct ionic_lif *lif) ...@@ -69,10 +93,12 @@ int ionic_rx_filters_init(struct ionic_lif *lif)
spin_lock_init(&lif->rx_filters.lock); spin_lock_init(&lif->rx_filters.lock);
spin_lock_bh(&lif->rx_filters.lock);
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]); INIT_HLIST_HEAD(&lif->rx_filters.by_hash[i]);
INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]); INIT_HLIST_HEAD(&lif->rx_filters.by_id[i]);
} }
spin_unlock_bh(&lif->rx_filters.lock);
return 0; return 0;
} }
...@@ -84,11 +110,13 @@ void ionic_rx_filters_deinit(struct ionic_lif *lif) ...@@ -84,11 +110,13 @@ void ionic_rx_filters_deinit(struct ionic_lif *lif)
struct hlist_node *tmp; struct hlist_node *tmp;
unsigned int i; unsigned int i;
spin_lock_bh(&lif->rx_filters.lock);
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) { for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
head = &lif->rx_filters.by_id[i]; head = &lif->rx_filters.by_id[i];
hlist_for_each_entry_safe(f, tmp, head, by_id) hlist_for_each_entry_safe(f, tmp, head, by_id)
ionic_rx_filter_free(lif, f); ionic_rx_filter_free(lif, f);
} }
spin_unlock_bh(&lif->rx_filters.lock);
} }
int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index, int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
...@@ -124,6 +152,7 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index, ...@@ -124,6 +152,7 @@ int ionic_rx_filter_save(struct ionic_lif *lif, u32 flow_id, u16 rxq_index,
f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id); f->filter_id = le32_to_cpu(ctx->comp.rx_filter_add.filter_id);
f->rxq_index = rxq_index; f->rxq_index = rxq_index;
memcpy(&f->cmd, ac, sizeof(f->cmd)); memcpy(&f->cmd, ac, sizeof(f->cmd));
netdev_dbg(lif->netdev, "rx_filter add filter_id %d\n", f->filter_id);
INIT_HLIST_NODE(&f->by_hash); INIT_HLIST_NODE(&f->by_hash);
INIT_HLIST_NODE(&f->by_id); INIT_HLIST_NODE(&f->by_id);
......
...@@ -161,12 +161,6 @@ static void ionic_rx_clean(struct ionic_queue *q, ...@@ -161,12 +161,6 @@ static void ionic_rx_clean(struct ionic_queue *q,
return; return;
} }
/* no packet processing while resetting */
if (unlikely(test_bit(IONIC_LIF_F_QUEUE_RESET, q->lif->state))) {
stats->dropped++;
return;
}
stats->pkts++; stats->pkts++;
stats->bytes += le16_to_cpu(comp->len); stats->bytes += le16_to_cpu(comp->len);
......
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