These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / intel / fm10k / fm10k_mbx.c
index 1b27383..af09a1b 100644 (file)
@@ -129,8 +129,8 @@ static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
  *  fm10k_fifo_drop_all - Drop all messages in FIFO
  *  @fifo: pointer to FIFO
  *
- *  This function resets the head pointer to drop all messages in the FIFO,
- *  and ensure the FIFO is empty.
+ *  This function resets the head pointer to drop all messages in the FIFO and
+ *  ensure the FIFO is empty.
  **/
 static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
 {
@@ -898,6 +898,27 @@ static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
        mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
 }
 
+/**
+ *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mailbox header
+ *  @mbx: pointer to mailbox
+ *
+ *  This function creates a fake disconnect header for loading into remote
+ *  mailbox header. The primary purpose is to prevent errors on immediate
+ *  start up after mbx->connect.
+ **/
+static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
+{
+       u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
+                 FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
+                 FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
+       u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
+
+       mbx->mbx_lock |= FM10K_MBX_ACK;
+
+       /* load header to memory to be written */
+       mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
+}
+
 /**
  *  fm10k_mbx_create_error_msg - Generate a error message
  *  @mbx: pointer to mailbox
@@ -1046,9 +1067,26 @@ static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
  **/
 static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
 {
+       u16 len, head, ack;
+
        /* reset our outgoing max size back to Rx limits */
        mbx->max_size = mbx->rx.size - 1;
 
+       /* update mbx->pulled to account for tail_len and ack */
+       head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
+       ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
+       mbx->pulled += mbx->tail_len - ack;
+
+       /* now drop any messages which have started or finished transmitting */
+       while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
+               len = fm10k_fifo_head_drop(&mbx->tx);
+               mbx->tx_dropped++;
+               if (mbx->pulled >= len)
+                       mbx->pulled -= len;
+               else
+                       mbx->pulled = 0;
+       }
+
        /* just do a quick resysnc to start of message */
        mbx->pushed = 0;
        mbx->pulled = 0;
@@ -1259,16 +1297,11 @@ static s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
                                   struct fm10k_mbx_info *mbx)
 {
        const u32 *hdr = &mbx->mbx_hdr;
-       s32 err_no;
        u16 head;
 
        /* we will need to pull all of the fields for verification */
        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
 
-       /* we only have lower 10 bits of error number so add upper bits */
-       err_no = FM10K_MSG_HDR_FIELD_GET(*hdr, ERR_NO);
-       err_no |= ~FM10K_MSG_HDR_MASK(ERR_NO);
-
        switch (mbx->state) {
        case FM10K_STATE_OPEN:
        case FM10K_STATE_DISCONNECT:
@@ -1423,8 +1456,10 @@ static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
        /* Place mbx in ready to connect state */
        mbx->state = FM10K_STATE_CONNECT;
 
+       fm10k_mbx_reset_work(mbx);
+
        /* initialize header of remote mailbox */
-       fm10k_mbx_create_disconnect_hdr(mbx);
+       fm10k_mbx_create_fake_disconnect_hdr(mbx);
        fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
 
        /* enable interrupt and notify other party of new message */
@@ -1730,7 +1765,7 @@ static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
        mbx->state = FM10K_STATE_CLOSED;
        mbx->remote = 0;
        fm10k_mbx_reset_work(mbx);
-       fm10k_mbx_update_max_size(mbx, 0);
+       fm10k_fifo_drop_all(&mbx->tx);
 
        fm10k_write_reg(hw, mbx->mbmem_reg, 0);
 }