mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
net: ibmveth: Reset the adapter when unexpected states are detected
Reset the adapter through new function ibmveth_reset, called in WARN_ON situations. Removed conflicting and unneeded forward declaration. Signed-off-by: Dave Marquardt <davemarq@linux.ibm.com> Link: https://patch.msgid.link/20250501194944.283729-3-davemarq@linux.ibm.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
b309785154
commit
2c91e2319e
|
|
@ -39,8 +39,6 @@
|
|||
#include "ibmveth.h"
|
||||
|
||||
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
|
||||
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
|
||||
bool reuse);
|
||||
static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev);
|
||||
|
||||
static struct kobj_type ktype_veth_pool;
|
||||
|
|
@ -231,7 +229,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
|
|||
index = pool->free_map[free_index];
|
||||
skb = NULL;
|
||||
|
||||
BUG_ON(index == IBM_VETH_INVALID_MAP);
|
||||
if (WARN_ON(index == IBM_VETH_INVALID_MAP)) {
|
||||
schedule_work(&adapter->work);
|
||||
goto bad_index_failure;
|
||||
}
|
||||
|
||||
/* are we allocating a new buffer or recycling an old one */
|
||||
if (pool->skbuff[index])
|
||||
|
|
@ -300,6 +301,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter,
|
|||
DMA_FROM_DEVICE);
|
||||
dev_kfree_skb_any(pool->skbuff[index]);
|
||||
pool->skbuff[index] = NULL;
|
||||
bad_index_failure:
|
||||
adapter->replenish_add_buff_failure++;
|
||||
|
||||
mb();
|
||||
|
|
@ -370,20 +372,36 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter,
|
|||
}
|
||||
}
|
||||
|
||||
/* remove a buffer from a pool */
|
||||
static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
|
||||
u64 correlator, bool reuse)
|
||||
/**
|
||||
* ibmveth_remove_buffer_from_pool - remove a buffer from a pool
|
||||
* @adapter: adapter instance
|
||||
* @correlator: identifies pool and index
|
||||
* @reuse: whether to reuse buffer
|
||||
*
|
||||
* Return:
|
||||
* * %0 - success
|
||||
* * %-EINVAL - correlator maps to pool or index out of range
|
||||
* * %-EFAULT - pool and index map to null skb
|
||||
*/
|
||||
static int ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
|
||||
u64 correlator, bool reuse)
|
||||
{
|
||||
unsigned int pool = correlator >> 32;
|
||||
unsigned int index = correlator & 0xffffffffUL;
|
||||
unsigned int free_index;
|
||||
struct sk_buff *skb;
|
||||
|
||||
BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
|
||||
BUG_ON(index >= adapter->rx_buff_pool[pool].size);
|
||||
if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
|
||||
WARN_ON(index >= adapter->rx_buff_pool[pool].size)) {
|
||||
schedule_work(&adapter->work);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb = adapter->rx_buff_pool[pool].skbuff[index];
|
||||
BUG_ON(skb == NULL);
|
||||
if (WARN_ON(!skb)) {
|
||||
schedule_work(&adapter->work);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* if we are going to reuse the buffer then keep the pointers around
|
||||
* but mark index as available. replenish will see the skb pointer and
|
||||
|
|
@ -411,6 +429,8 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter,
|
|||
mb();
|
||||
|
||||
atomic_dec(&(adapter->rx_buff_pool[pool].available));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the current buffer on the rx queue */
|
||||
|
|
@ -420,24 +440,44 @@ static inline struct sk_buff *ibmveth_rxq_get_buffer(struct ibmveth_adapter *ada
|
|||
unsigned int pool = correlator >> 32;
|
||||
unsigned int index = correlator & 0xffffffffUL;
|
||||
|
||||
BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
|
||||
BUG_ON(index >= adapter->rx_buff_pool[pool].size);
|
||||
if (WARN_ON(pool >= IBMVETH_NUM_BUFF_POOLS) ||
|
||||
WARN_ON(index >= adapter->rx_buff_pool[pool].size)) {
|
||||
schedule_work(&adapter->work);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return adapter->rx_buff_pool[pool].skbuff[index];
|
||||
}
|
||||
|
||||
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
|
||||
bool reuse)
|
||||
/**
|
||||
* ibmveth_rxq_harvest_buffer - Harvest buffer from pool
|
||||
*
|
||||
* @adapter: pointer to adapter
|
||||
* @reuse: whether to reuse buffer
|
||||
*
|
||||
* Context: called from ibmveth_poll
|
||||
*
|
||||
* Return:
|
||||
* * %0 - success
|
||||
* * other - non-zero return from ibmveth_remove_buffer_from_pool
|
||||
*/
|
||||
static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
|
||||
bool reuse)
|
||||
{
|
||||
u64 cor;
|
||||
int rc;
|
||||
|
||||
cor = adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator;
|
||||
ibmveth_remove_buffer_from_pool(adapter, cor, reuse);
|
||||
rc = ibmveth_remove_buffer_from_pool(adapter, cor, reuse);
|
||||
if (unlikely(rc))
|
||||
return rc;
|
||||
|
||||
if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
|
||||
adapter->rx_queue.index = 0;
|
||||
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
|
||||
|
|
@ -709,6 +749,35 @@ static int ibmveth_close(struct net_device *netdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmveth_reset - Handle scheduled reset work
|
||||
*
|
||||
* @w: pointer to work_struct embedded in adapter structure
|
||||
*
|
||||
* Context: This routine acquires rtnl_mutex and disables its NAPI through
|
||||
* ibmveth_close. It can't be called directly in a context that has
|
||||
* already acquired rtnl_mutex or disabled its NAPI, or directly from
|
||||
* a poll routine.
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
static void ibmveth_reset(struct work_struct *w)
|
||||
{
|
||||
struct ibmveth_adapter *adapter = container_of(w, struct ibmveth_adapter, work);
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
netdev_dbg(netdev, "reset starting\n");
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
dev_close(adapter->netdev);
|
||||
dev_open(adapter->netdev, NULL);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
netdev_dbg(netdev, "reset complete\n");
|
||||
}
|
||||
|
||||
static int ibmveth_set_link_ksettings(struct net_device *dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
|
|
@ -1324,7 +1393,8 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
|
|||
wmb(); /* suggested by larson1 */
|
||||
adapter->rx_invalid_buffer++;
|
||||
netdev_dbg(netdev, "recycling invalid buffer\n");
|
||||
ibmveth_rxq_harvest_buffer(adapter, true);
|
||||
if (unlikely(ibmveth_rxq_harvest_buffer(adapter, true)))
|
||||
break;
|
||||
} else {
|
||||
struct sk_buff *skb, *new_skb;
|
||||
int length = ibmveth_rxq_frame_length(adapter);
|
||||
|
|
@ -1334,6 +1404,8 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
|
|||
__sum16 iph_check = 0;
|
||||
|
||||
skb = ibmveth_rxq_get_buffer(adapter);
|
||||
if (unlikely(!skb))
|
||||
break;
|
||||
|
||||
/* if the large packet bit is set in the rx queue
|
||||
* descriptor, the mss will be written by PHYP eight
|
||||
|
|
@ -1357,10 +1429,12 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
|
|||
if (rx_flush)
|
||||
ibmveth_flush_buffer(skb->data,
|
||||
length + offset);
|
||||
ibmveth_rxq_harvest_buffer(adapter, true);
|
||||
if (unlikely(ibmveth_rxq_harvest_buffer(adapter, true)))
|
||||
break;
|
||||
skb = new_skb;
|
||||
} else {
|
||||
ibmveth_rxq_harvest_buffer(adapter, false);
|
||||
if (unlikely(ibmveth_rxq_harvest_buffer(adapter, false)))
|
||||
break;
|
||||
skb_reserve(skb, offset);
|
||||
}
|
||||
|
||||
|
|
@ -1407,7 +1481,10 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
|
|||
* then check once more to make sure we are done.
|
||||
*/
|
||||
lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE);
|
||||
BUG_ON(lpar_rc != H_SUCCESS);
|
||||
if (WARN_ON(lpar_rc != H_SUCCESS)) {
|
||||
schedule_work(&adapter->work);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ibmveth_rxq_pending_buffer(adapter) && napi_schedule(napi)) {
|
||||
lpar_rc = h_vio_signal(adapter->vdev->unit_address,
|
||||
|
|
@ -1428,7 +1505,7 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
|
|||
if (napi_schedule_prep(&adapter->napi)) {
|
||||
lpar_rc = h_vio_signal(adapter->vdev->unit_address,
|
||||
VIO_IRQ_DISABLE);
|
||||
BUG_ON(lpar_rc != H_SUCCESS);
|
||||
WARN_ON(lpar_rc != H_SUCCESS);
|
||||
__napi_schedule(&adapter->napi);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -1670,6 +1747,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
|
|||
|
||||
adapter->vdev = dev;
|
||||
adapter->netdev = netdev;
|
||||
INIT_WORK(&adapter->work, ibmveth_reset);
|
||||
adapter->mcastFilterSize = be32_to_cpu(*mcastFilterSize_p);
|
||||
ibmveth_init_link_settings(netdev);
|
||||
|
||||
|
|
@ -1762,6 +1840,8 @@ static void ibmveth_remove(struct vio_dev *dev)
|
|||
struct ibmveth_adapter *adapter = netdev_priv(netdev);
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&adapter->work);
|
||||
|
||||
for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
|
||||
kobject_put(&adapter->rx_buff_pool[i].kobj);
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ struct ibmveth_adapter {
|
|||
struct vio_dev *vdev;
|
||||
struct net_device *netdev;
|
||||
struct napi_struct napi;
|
||||
struct work_struct work;
|
||||
unsigned int mcastFilterSize;
|
||||
void *buffer_list_addr;
|
||||
void *filter_list_addr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user