forked from Minki/linux
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4932893924
@ -103,15 +103,18 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
|
||||
void *p)
|
||||
{
|
||||
struct ionic_lif *lif = netdev_priv(netdev);
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
|
||||
regs->version = IONIC_DEV_CMD_REG_VERSION;
|
||||
|
||||
offset = 0;
|
||||
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);
|
||||
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,
|
||||
|
@ -96,8 +96,7 @@ static void ionic_link_status_check(struct ionic_lif *lif)
|
||||
u16 link_status;
|
||||
bool link_up;
|
||||
|
||||
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state) ||
|
||||
test_bit(IONIC_LIF_F_QUEUE_RESET, lif->state))
|
||||
if (!test_bit(IONIC_LIF_F_LINK_CHECK_REQUESTED, lif->state))
|
||||
return;
|
||||
|
||||
link_status = le16_to_cpu(lif->info->status.link_status);
|
||||
@ -114,16 +113,22 @@ static void ionic_link_status_check(struct ionic_lif *lif)
|
||||
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);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
} else {
|
||||
if (netif_carrier_ok(netdev)) {
|
||||
netdev_info(netdev, "Link down\n");
|
||||
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);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (f)
|
||||
return 0;
|
||||
|
||||
netdev_dbg(lif->netdev, "rx_filter add ADDR %pM (id %d)\n", addr,
|
||||
ctx.comp.rx_filter_add.filter_id);
|
||||
netdev_dbg(lif->netdev, "rx_filter add ADDR %pM\n", addr);
|
||||
|
||||
memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
|
||||
err = ionic_adminq_post_wait(lif, &ctx);
|
||||
@ -893,6 +897,9 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
|
||||
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);
|
||||
ionic_rx_filter_free(lif, f);
|
||||
spin_unlock_bh(&lif->rx_filters.lock);
|
||||
@ -901,9 +908,6 @@ static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr)
|
||||
if (err && err != -EEXIST)
|
||||
return err;
|
||||
|
||||
netdev_dbg(lif->netdev, "rx_filter del ADDR %pM (id %d)\n", addr,
|
||||
ctx.cmd.rx_filter_del.filter_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1351,13 +1355,11 @@ static int ionic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto,
|
||||
};
|
||||
int err;
|
||||
|
||||
netdev_dbg(netdev, "rx_filter add VLAN %d\n", vid);
|
||||
err = ionic_adminq_post_wait(lif, &ctx);
|
||||
if (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);
|
||||
}
|
||||
|
||||
@ -1382,8 +1384,8 @@ static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n", vid,
|
||||
le32_to_cpu(ctx.cmd.rx_filter_del.filter_id));
|
||||
netdev_dbg(netdev, "rx_filter del VLAN %d (id %d)\n",
|
||||
vid, f->filter_id);
|
||||
|
||||
ctx.cmd.rx_filter_del.filter_id = cpu_to_le32(f->filter_id);
|
||||
ionic_rx_filter_free(lif, f);
|
||||
@ -1993,16 +1995,13 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
|
||||
bool running;
|
||||
int err = 0;
|
||||
|
||||
err = ionic_wait_for_bit(lif, IONIC_LIF_F_QUEUE_RESET);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&lif->queue_lock);
|
||||
running = netif_running(lif->netdev);
|
||||
if (running) {
|
||||
netif_device_detach(lif->netdev);
|
||||
err = ionic_stop(lif->netdev);
|
||||
if (err)
|
||||
goto reset_out;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (cb)
|
||||
@ -2012,9 +2011,7 @@ int ionic_reset_queues(struct ionic_lif *lif, ionic_reset_cb cb, void *arg)
|
||||
err = ionic_open(lif->netdev);
|
||||
netif_device_attach(lif->netdev);
|
||||
}
|
||||
|
||||
reset_out:
|
||||
clear_bit(IONIC_LIF_F_QUEUE_RESET, lif->state);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -2161,7 +2158,9 @@ static void ionic_lif_handle_fw_down(struct ionic_lif *lif)
|
||||
|
||||
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
|
||||
dev_info(ionic->dev, "Surprise FW stop, stopping queues\n");
|
||||
mutex_lock(&lif->queue_lock);
|
||||
ionic_stop_queues(lif);
|
||||
mutex_unlock(&lif->queue_lock);
|
||||
}
|
||||
|
||||
if (netif_running(lif->netdev)) {
|
||||
@ -2280,15 +2279,15 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
|
||||
cancel_work_sync(&lif->deferred.work);
|
||||
cancel_work_sync(&lif->tx_timeout_work);
|
||||
ionic_rx_filters_deinit(lif);
|
||||
if (lif->netdev->features & NETIF_F_RXHASH)
|
||||
ionic_lif_rss_deinit(lif);
|
||||
}
|
||||
|
||||
if (lif->netdev->features & NETIF_F_RXHASH)
|
||||
ionic_lif_rss_deinit(lif);
|
||||
|
||||
napi_disable(&lif->adminqcq->napi);
|
||||
ionic_lif_qcq_deinit(lif, lif->notifyqcq);
|
||||
ionic_lif_qcq_deinit(lif, lif->adminqcq);
|
||||
|
||||
mutex_destroy(&lif->queue_lock);
|
||||
ionic_lif_reset(lif);
|
||||
}
|
||||
|
||||
@ -2465,6 +2464,7 @@ static int ionic_lif_init(struct ionic_lif *lif)
|
||||
return err;
|
||||
|
||||
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 */
|
||||
lif->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
|
||||
|
@ -135,7 +135,6 @@ enum ionic_lif_state_flags {
|
||||
IONIC_LIF_F_SW_DEBUG_STATS,
|
||||
IONIC_LIF_F_UP,
|
||||
IONIC_LIF_F_LINK_CHECK_REQUESTED,
|
||||
IONIC_LIF_F_QUEUE_RESET,
|
||||
IONIC_LIF_F_FW_RESET,
|
||||
|
||||
/* leave this as last */
|
||||
@ -165,6 +164,7 @@ struct ionic_lif {
|
||||
unsigned int hw_index;
|
||||
unsigned int kern_pid;
|
||||
u64 __iomem *kern_dbpage;
|
||||
struct mutex queue_lock; /* lock for queue structures */
|
||||
spinlock_t adminq_lock; /* lock for AdminQ operations */
|
||||
struct ionic_qcq *adminqcq;
|
||||
struct ionic_qcq *notifyqcq;
|
||||
@ -213,12 +213,6 @@ struct ionic_lif {
|
||||
#define lif_to_txq(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)
|
||||
{
|
||||
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)
|
||||
void ionic_rx_filter_replay(struct ionic_lif *lif)
|
||||
{
|
||||
struct ionic_rx_filter_add_cmd *ac;
|
||||
struct hlist_head new_id_list;
|
||||
struct ionic_admin_ctx ctx;
|
||||
struct ionic_rx_filter *f;
|
||||
struct hlist_head *head;
|
||||
struct hlist_node *tmp;
|
||||
unsigned int key;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
INIT_HLIST_HEAD(&new_id_list);
|
||||
ac = &ctx.cmd.rx_filter_add;
|
||||
|
||||
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
|
||||
@ -58,9 +61,30 @@ void ionic_rx_filter_replay(struct ionic_lif *lif)
|
||||
ac->mac.addr);
|
||||
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)
|
||||
@ -69,10 +93,12 @@ int ionic_rx_filters_init(struct ionic_lif *lif)
|
||||
|
||||
spin_lock_init(&lif->rx_filters.lock);
|
||||
|
||||
spin_lock_bh(&lif->rx_filters.lock);
|
||||
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_id[i]);
|
||||
}
|
||||
spin_unlock_bh(&lif->rx_filters.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -84,11 +110,13 @@ void ionic_rx_filters_deinit(struct ionic_lif *lif)
|
||||
struct hlist_node *tmp;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock_bh(&lif->rx_filters.lock);
|
||||
for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
|
||||
head = &lif->rx_filters.by_id[i];
|
||||
hlist_for_each_entry_safe(f, tmp, head, by_id)
|
||||
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,
|
||||
@ -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->rxq_index = rxq_index;
|
||||
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_id);
|
||||
|
@ -161,12 +161,6 @@ static void ionic_rx_clean(struct ionic_queue *q,
|
||||
return;
|
||||
}
|
||||
|
||||
/* no packet processing while resetting */
|
||||
if (unlikely(test_bit(IONIC_LIF_F_QUEUE_RESET, q->lif->state))) {
|
||||
stats->dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
stats->pkts++;
|
||||
stats->bytes += le16_to_cpu(comp->len);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user