/* Get the interrupt sources triggered by VFs */
errsou3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRSOU3);
sources = ADF_GEN2_ERR_REG_VF2PF(errsou3);
if (!sources) return0;
/* Get the already disabled interrupts */
errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_GEN2_ERRMSK3);
disabled = ADF_GEN2_ERR_REG_VF2PF(errmsk3);
pending = sources & ~disabled; if (!pending) return0;
/* Due to HW limitations, when disabling the interrupts, we can't *justdisabletherequestedsources,asthiswouldleadtomissed *interruptsifERRSOU3changesjustbeforewritingtoERRMSK3. *Toworkaroundit,disableallandre-enableonlythesourcesthat *arenotinvf_maskandwerenotalreadydisabled.Re-enablingwill *triggeranewinterruptforthesourcesthathavechangedinthe *meantime,ifany.
*/
errmsk3 |= ADF_GEN2_ERR_MSK_VF2PF(ADF_GEN2_VF_MSK);
ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
/* Update only section of errmsk3 related to VF2PF */
errmsk3 &= ~ADF_GEN2_ERR_MSK_VF2PF(ADF_GEN2_VF_MSK);
errmsk3 |= ADF_GEN2_ERR_MSK_VF2PF(sources | disabled);
ADF_CSR_WR(pmisc_addr, ADF_GEN2_ERRMSK3, errmsk3);
/* Return the sources of the (new) interrupt(s) */ return pending;
}
/* Gen2 messages, both PF->VF and VF->PF, are all 16 bits long. This *allowsustobuildandreadmessagesasiftheywhereall0based. *However,sendandreceiveareinasingleshared32bitsregister, *soweneedtoshiftand/ormaskthemessagehalfbeforedecoding *itandafterencodingit.Whichonetoshiftdependsonthe *direction.
*/
int_bit = gen2_csr_get_int_bit(local_offset);
csr_msg = adf_pfvf_csr_msg_of(accel_dev, msg, &csr_gen2_fmt); if (unlikely(!csr_msg)) return -EINVAL;
/* Prepare for CSR format, shifting the wire message in place and *settingtheinusepattern
*/
csr_msg = gen2_csr_msg_to_position(csr_msg, local_offset);
gen2_csr_set_in_use(&csr_msg, remote_offset);
mutex_lock(lock);
start: /* Check if the PFVF CSR is in use by remote function */
csr_val = ADF_CSR_RD(pmisc_addr, pfvf_offset); if (gen2_csr_is_in_use(csr_val, local_offset)) {
dev_dbg(&GET_DEV(accel_dev), "PFVF CSR in use by remote function\n"); goto retry;
}
/* Attempt to get ownership of the PFVF CSR */
ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_msg | int_bit);
/* Wait for confirmation from remote func it received the message */
ret = read_poll_timeout(ADF_CSR_RD, csr_val, !(csr_val & int_bit),
ADF_PFVF_MSG_ACK_DELAY_US,
ADF_PFVF_MSG_ACK_MAX_DELAY_US, true, pmisc_addr, pfvf_offset); if (unlikely(ret < 0)) {
dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");
csr_val &= ~int_bit;
}
/* For fire-and-forget notifications, the receiver does not clear *thein-usepattern.Thisisusedtodetectcollisions.
*/ if (params->is_notification_message(msg.type) && csr_val != csr_msg) { /* Collision must have overwritten the message */
dev_err(&GET_DEV(accel_dev), "Collision on notification - PFVF CSR overwritten by remote function\n"); goto retry;
}
/* If the far side did not clear the in-use pattern it is either *1)Notification-messageleftintacttodetectcollision *2)Olderprotocol(compatibilityversion<3)onthefarside *wherethesenderisresponsibleforclearingthein-use *patternafterthereceivedhasacknowledgedreceipt. *Ineithercase,clearthein-usepatternnow.
*/ if (gen2_csr_is_in_use(csr_val, remote_offset)) {
gen2_csr_clear_in_use(&csr_val, remote_offset);
ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val);
}
out:
mutex_unlock(lock); return ret;
retry: if (--retries) {
msleep(ADF_PFVF_MSG_RETRY_DELAY); goto start;
} else {
ret = -EBUSY; goto out;
}
}
/* Extract the message from the CSR */
csr_msg = gen2_csr_msg_from_position(csr_val, local_offset);
/* Ignore legacy non-system (non-kernel) messages */ if (unlikely(is_legacy_user_pfvf_message(csr_msg))) {
dev_dbg(&GET_DEV(accel_dev), "Ignored non-system message (0x%.8x);\n", csr_val); /* Because this must be a legacy message, the far side *mustclearthein-usepattern,sodon'tdoit.
*/ return msg;
}
/* Return the pfvf_message format */
msg = adf_pfvf_message_of(accel_dev, csr_msg, &csr_gen2_fmt);
/* The in-use pattern is not cleared for notifications (so that *itcanbeusedforcollisiondetection)orolderimplementations
*/ if (params->compat_ver >= ADF_PFVF_COMPAT_FAST_ACK &&
!params->is_notification_message(msg.type))
gen2_csr_clear_in_use(&csr_val, remote_offset);
/* To ACK, clear the INT bit */
csr_val &= ~int_bit;
ADF_CSR_WR(pmisc_addr, pfvf_offset, csr_val);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.