OK, I will add a dev param to this the fsl_mc_io_create() function, toI disagree. I don't see why the alternative you suggest makes the code "much simpler".
+int __must_check fsl_create_mc_io(phys_addr_t mc_portal_phys_addr,
+ uint32_t mc_portal_size,
+ uint32_t flags, struct fsl_mc_io **new_mc_io)
+{
+ int error = -EINVAL;
+ struct fsl_mc_io *mc_io = NULL;
+
+ mc_io = kzalloc(sizeof(*mc_io), GFP_KERNEL);
+ if (mc_io == NULL) {
+ error = -ENOMEM;
+ pr_err("No memory to allocate mc_io\n");
+ goto error;
+ }
+
+ mc_io->magic = FSL_MC_IO_MAGIC;
+ mc_io->flags = flags;
+ mc_io->portal_phys_addr = mc_portal_phys_addr;
+ mc_io->portal_size = mc_portal_size;
+ spin_lock_init(&mc_io->spinlock);
+ error = map_mc_portal(mc_portal_phys_addr,
+ mc_portal_size, &mc_io->portal_virt_addr);
+ if (error < 0)
+ goto error;
+
+ *new_mc_io = mc_io;
+ return 0;
if a fn only returns an address or error, it can return ERR_PTR
(e.g., -ENOMEM), and the callsite use IS_ERR() to determine whether
there was an error or address returned. This makes code much
simpler instead of passing address values back by reference.
No. We cannot use devm_ functions here as there is no device passed in.+error:
+ if (mc_io != NULL) {
+ if (mc_io->portal_virt_addr != NULL) {
+ unmap_mc_portal(mc_portal_phys_addr,
+ mc_portal_size,
+ mc_io->portal_virt_addr);
+ }
+
+ kfree(mc_io);
kfree can handle being passed NULL, but again, might want to
consider using devm_ functions instead.
Is it a good idea to lose your device context in any function? Whenever I dropped contexts in helper I usually ended up regretting it later ;).
I will change the value of the timeout to be a function of HZ instead of a hard-coded jiffies value. Also, to avoid future confusion, I'llThat is not true. The 100 is in jiffies not in usec:+ if (mc_io->flags & FSL_MC_IO_PORTAL_SHARED) {
+ spin_lock_irqsave(&mc_io->spinlock, irqsave_flags);
+ lock_acquired = true;
+ }
+
+ mc_write_command(mc_io->portal_virt_addr, cmd);
+
+ for (;;) {
+ status = mc_read_response(mc_io->portal_virt_addr, cmd);
+ if (status != MC_CMD_STATUS_READY)
+ break;
+
+ /*
+ * TODO: When MC command completion interrupts are supported
+ * call wait function here instead of udelay()
+ */
+ udelay(MC_CMD_COMPLETION_POLLING_INTERVAL);
+ if (time_after_eq(jiffies, jiffies_until_timeout)) {
+ error = -ETIMEDOUT;
+ goto out;
+ }
+ }
+
+ error = mc_status_to_error(status);
+out:
+ if (lock_acquired)
+ spin_unlock_irqrestore(&mc_io->spinlock, irqsave_flags);
so if the portal is shared, we take a lock, disable interrupts, and
then potentially udelay for a whopping 500usec, then check to see if
_100_usec have passed, and thus _always_ issue a timeout error, even
if the device took < 100usec to consume the command???
If you always wait for 100 jiffies, the timeout code suddenly depends on the HZ value which is kernel configuration, no? Wouldn't it be better to base the timeout on real wall time?
I will keep only the major version check and remove the minor version check.
/**
* Timeout in jiffies to wait for the completion of an MC command
*/
#define MC_CMD_COMPLETION_TIMEOUT 100
/**
* Delay in microseconds between polling iterations while
* waiting for MC command completion
*/
#define MC_CMD_COMPLETION_POLLING_INTERVAL 500
Not to mention this code will spin perpetually with IRQs disabled ifI agree that disabling interrupts while doing polling is not efficient. I was assuming the worst case scenario of sharing the portal: both
the read_response never returns ready. I also don't see a reason
why IRQs are being disabled in the first place - it's not being used
in an IRQ handler...perhaps we need to wait until command completion
IRQs are supported :)
threads and interrupt handlers accessing the same portal at the same time. If only threads access the same portal, we don't need to disable interrupts and even further we can use a mutex instead of a spinlock.
If only interrupt handlers access a given portal (from multiple CPUs)
we have use a spinlock but we don't need to disabel interrupts.
If both threads and interrupt handlers access a given portal, then
we need to both use a spinlock and disable interrupts
I will change synchronization logic in the v2 respin to avoid
disabling interrupts in the first two cases above.
This comment is not precise enough be actionable.+/**
+ * @brief Management Complex firmware version information
+ */
+#define MC_VER_MAJOR 2
+#define MC_VER_MINOR 0
code should be adjusted to run on all *compatible* versions of h/w,
not strictly the one set in these defines.
What exactly you want to be changed here?
I think the easy thing to do is to convert the exact version check into a ranged version check: have minimum and maximum versions you support. Or a list of exact versions you support. Or not check for the version at all - or only for the major version and guarantee that the major version indicates backwards compatibility.
Stuart already answered this question.
This is because this file is using doxygen comments, as it was developed+/**
+ * @brief Disconnects one endpoint to remove its network link
+ *
+ * @param[in] mc_io Pointer to opaque I/O object
+ * @param[in] dprc_handle Handle to the DPRC object
+ * @param[in] endpoint Endpoint configuration parameters.
+ *
+ * @returns '0' on Success; Error code otherwise.
+ * */
+int dprc_disconnect(struct fsl_mc_io *mc_io, uint16_t dprc_handle,
+ struct dprc_endpoint *endpoint);
+
+/*! @} */
this entire file is riddled with non-kernel-doc comment markers: see
Documentation/kernel-doc-nano-HOWTO.txt on how to write function and
other types of comments in a kernel-doc compliant format.
by another team. Unless someone else has an objection, I will leave the doxygen comments alone and not make any change here.
Do you see any other source files in Linux using doxygen comments? Mixing different documentation styles can easily become a big mess, because you can't generate external documentation consistently for the whole tree.
Alex--