* @skb: skb to give to the IO partition
*
* Send the skb to the IO Partition.
- * Returns void
+ * Returns 0 or error
*/
-static void
+static int
post_skb(struct uiscmdrsp *cmdrsp,
struct visornic_devdata *devdata, struct sk_buff *skb)
{
+ int err;
+
cmdrsp->net.buf = skb;
cmdrsp->net.rcvpost.frag.pi_pfn = page_to_pfn(virt_to_page(skb->data));
cmdrsp->net.rcvpost.frag.pi_off =
cmdrsp->net.rcvpost.frag.pi_len = skb->len;
cmdrsp->net.rcvpost.unique_num = devdata->incarnation_id;
- if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) <= PI_PAGE_SIZE) {
- cmdrsp->net.type = NET_RCV_POST;
- cmdrsp->cmdtype = CMD_NET_TYPE;
- if (!visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- cmdrsp)) {
- atomic_inc(&devdata->num_rcvbuf_in_iovm);
- devdata->chstat.sent_post++;
- } else {
- devdata->chstat.sent_post_failed++;
- }
+ if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) > PI_PAGE_SIZE)
+ return -EINVAL;
+
+ cmdrsp->net.type = NET_RCV_POST;
+ cmdrsp->cmdtype = CMD_NET_TYPE;
+ err = visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp);
+ if (err) {
+ devdata->chstat.sent_post_failed++;
+ return err;
}
+
+ atomic_inc(&devdata->num_rcvbuf_in_iovm);
+ devdata->chstat.sent_post++;
+
+ return 0;
}
/*
* @devdata: visornic device we are enabling/disabling
*
* Send the enable/disable message to the IO Partition.
- * Returns void
+ * Returns 0 or error
*/
-static void
+static int
send_enbdis(struct net_device *netdev, int state,
struct visornic_devdata *devdata)
{
+ int err;
+
devdata->cmdrsp_rcv->net.enbdis.enable = state;
devdata->cmdrsp_rcv->net.enbdis.context = netdev;
devdata->cmdrsp_rcv->net.type = NET_RCV_ENBDIS;
devdata->cmdrsp_rcv->cmdtype = CMD_NET_TYPE;
- if (!visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- devdata->cmdrsp_rcv))
- devdata->chstat.sent_enbdis++;
+ err = visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ devdata->cmdrsp_rcv);
+ if (err)
+ return err;
+ devdata->chstat.sent_enbdis++;
+ return 0;
}
/*
int i;
unsigned long flags;
int wait = 0;
+ int err;
/* send a msg telling the other end we are stopping incoming pkts */
spin_lock_irqsave(&devdata->priv_lock, flags);
/* send disable and wait for ack -- don't hold lock when sending
* disable because if the queue is full, insert might sleep.
+ * If an error occurs, don't wait for the timeout.
*/
- send_enbdis(netdev, 0, devdata);
+ err = send_enbdis(netdev, 0, devdata);
+ if (err)
+ return err;
/* wait for ack to arrive before we try to free rcv buffers
* NOTE: the other end automatically unposts the rcv buffers when
static int
init_rcv_bufs(struct net_device *netdev, struct visornic_devdata *devdata)
{
- int i, count;
+ int i, j, count, err;
/* allocate fixed number of receive buffers to post to uisnic
* post receive buffers after we've allocated a required amount
* lock - we've not enabled nor started the queue so there shouldn't
* be any rcv or xmit activity
*/
- for (i = 0; i < count; i++)
- post_skb(devdata->cmdrsp_rcv, devdata, devdata->rcvbuf[i]);
+ for (i = 0; i < count; i++) {
+ err = post_skb(devdata->cmdrsp_rcv, devdata,
+ devdata->rcvbuf[i]);
+ if (!err)
+ continue;
+
+ /* Error handling -
+ * If we posted at least one skb, we should return success,
+ * but need to free the resources that we have not successfully
+ * posted.
+ */
+ for (j = i; j < count; j++) {
+ kfree_skb(devdata->rcvbuf[j]);
+ devdata->rcvbuf[j] = NULL;
+ }
+ if (i == 0)
+ return err;
+ break;
+ }
return 0;
}
static int
visornic_enable_with_timeout(struct net_device *netdev, const int timeout)
{
- int i;
+ int err = 0;
struct visornic_devdata *devdata = netdev_priv(netdev);
unsigned long flags;
int wait = 0;
/* NOTE: the other end automatically unposts the rcv buffers when it
* gets a disable.
*/
- i = init_rcv_bufs(netdev, devdata);
- if (i < 0) {
+ err = init_rcv_bufs(netdev, devdata);
+ if (err < 0) {
dev_err(&netdev->dev,
- "%s failed to init rcv bufs (%d)\n", __func__, i);
- return i;
+ "%s failed to init rcv bufs\n", __func__);
+ return err;
}
spin_lock_irqsave(&devdata->priv_lock, flags);
spin_unlock_irqrestore(&devdata->priv_lock, flags);
/* send enable and wait for ack -- don't hold lock when sending enable
- * because if the queue is full, insert might sleep.
+ * because if the queue is full, insert might sleep. If an error
+ * occurs error out.
*/
- send_enbdis(netdev, 1, devdata);
+ err = send_enbdis(netdev, 1, devdata);
+ if (err)
+ return err;
spin_lock_irqsave(&devdata->priv_lock, flags);
while ((timeout == VISORNIC_INFINITE_RSP_WAIT) ||
int len, firstfraglen, padlen;
struct uiscmdrsp *cmdrsp = NULL;
unsigned long flags;
+ int err;
devdata = netdev_priv(netdev);
spin_lock_irqsave(&devdata->priv_lock, flags);
return NETDEV_TX_OK;
}
- if (visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART, cmdrsp)) {
+ err = visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART, cmdrsp);
+ if (err) {
netif_stop_queue(netdev);
spin_unlock_irqrestore(&devdata->priv_lock, flags);
devdata->busy_cnt++;
{
struct uiscmdrsp *cmdrsp;
struct visornic_devdata *devdata = netdev_priv(netdev);
+ int err = 0;
if (devdata->old_flags == netdev->flags)
return;
cmdrsp->net.enbdis.context = netdev;
cmdrsp->net.enbdis.enable =
netdev->flags & IFF_PROMISC;
- visorchannel_signalinsert(devdata->dev->visorchannel,
- IOCHAN_TO_IOPART,
- cmdrsp);
+ err = visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp);
kfree(cmdrsp);
+ if (err)
+ return;
out_save_flags:
devdata->old_flags = netdev->flags;
status = -ENOMEM;
break;
}
- post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ status = post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ if (status) {
+ kfree_skb(devdata->rcvbuf[i]);
+ devdata->rcvbuf[i] = NULL;
+ break;
+ }
numreposted++;
break;
}
* Send receive buffers to the IO Partition.
* Returns void
*/
-static void
+static int
send_rcv_posts_if_needed(struct visornic_devdata *devdata)
{
int i;
struct net_device *netdev;
struct uiscmdrsp *cmdrsp = devdata->cmdrsp_rcv;
int cur_num_rcv_bufs_to_alloc, rcv_bufs_allocated;
+ int err;
/* don't do this until vnic is marked ready */
if (!(devdata->enabled && devdata->enab_dis_acked))
- return;
+ return 0;
netdev = devdata->netdev;
rcv_bufs_allocated = 0;
break;
}
rcv_bufs_allocated++;
- post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ err = post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ if (err) {
+ kfree_skb(devdata->rcvbuf[i]);
+ devdata->rcvbuf[i] = NULL;
+ break;
+ }
devdata->chstat.extra_rcvbufs_sent++;
}
}
devdata->num_rcv_bufs_could_not_alloc -= rcv_bufs_allocated;
+ return 0;
}
/*
struct visornic_devdata,
napi);
int rx_count = 0;
+ int err;
+
+ err = send_rcv_posts_if_needed(devdata);
+ if (err)
+ return err;
- send_rcv_posts_if_needed(devdata);
service_resp_queue(devdata->cmdrsp, devdata, &rx_count, budget);
/* If there aren't any more packets to receive stop the poll */