Ira W. Snyder wrote:
> On Mon, Feb 15, 2010 at 06:13:11PM +0100, Wolfgang Grandegger wrote:
>> Hi Ira,
>>
>> Ira W. Snyder wrote:
>>> +/* Get the MSYNC bits from the "old-style" interface control registers */
>>> +static void janz_get_msync(struct janz_ican3 *mod, u8 *locl, u8 *peer)
>>> +{
>>> + janz_set_page(mod, 0);
>>> + *peer = ioread8(mod->regs + MSYNC_PEER);
>>> + *locl = ioread8(mod->regs + MSYNC_LOCL);
>>> +}
>> What are your arguments against using structures to describe the
>> register layout?
>>
>
> I don't have any strong arguments against using a structure to describe
> register layout, except:
>
> 1) all datasheets I've ever used have registers described by hexadecimal
> offsets. Using a structure, you have to manually calculate offsets when
> checking that the structure is defined correctly. Once it is correct,
> this isn't a big deal.
In general structs are preferred as they allow type checking and result
usually in more readable code. #defines are more handy if you deal with
offset instead of addresses.
> 2) These registers only exist in a single DPM page, page #0. They are
> not "always accessible", as in a device which uses mmio. You must switch
> the DPM page before accessing them.
>
> Does it really make sense to create a structure just for calculating the
> offsets in one DPM page? For the "janz onboard registers" (described
> with "JANZ_OB_* defines), I agree. I'll make a structure for those.
Please check if it results in better code.
[snip]
>>> + if ((xord & 0x30) == 0x30) {
>>> + dev_err(mod->dev, "no mbox for writing\n");
>>> + return -ENOMEM;
>>> + }
>> Here and in many other places macro definitions would make the code more
>> readable.
>>
>
> Yep, There are a few of these. My problem is this: what names do I use?
> The way this device works is stupid. You'll want to read pages C-333 to
> C-335 in the manual.
>
> The basics are:
> You have two registers, MSYNC_PEER and MSYNC_LOCL. The firmware can
> only write to MSYNC_PEER, and the driver can only write to MSYNC_LOCL.
>
> The registers are laid out like this:
>
> MSYNC_PEER:
> bit0: RB0
> bit1: RB1
> bit2: LW
> bit4: WB0
> bit5: WB1
>
> MSYNC_LOCL:
> bit0: RB0
> bit1: RB1
> bit4: WB0
> bit5: WB1
> bit6: LW
>
> When you get an interrupt, and you want to read a message from the
> controller, you must XOR the RBn bits. If you get a 1 back for a certain
> bit position, then you have a buffer to read. The same is true for the
> WBn bits, except that the XOR will be 0 when you have a buffer to read.
>
> In addition, you must read/set the LW (last written) bit to correspond
> to the buffer you last wrote to.
>
> I would be happy to use defines to make this easier to read, but I have
> *no idea* what to name them. Suggestions please.
#define MSYNC_PEER_RB0 0x01
#define MSYNC_PEER_RB1 0x02
and so on.
BTW: an inline function for that bit gymnastics would be useful as well.
[snip]
>>> + memset(&msg, 0, sizeof(msg));
>>> + msg.control = 0x00;
>>> + msg.spec = MSG_INITFDPMQUEUE;
>>> + msg.len = cpu_to_le16(8);
>> Please do not align expressions. Just use *one* space before and after
>> "=". Please fix globally.
>>
>
> Ok. This will be in the next version of the patch. I thought it made the
> code easier to read.
It's required by the coding style.
>>> +static void can_to_janz(struct janz_ican3 *mod, struct can_frame *cf,
>>> + struct janz_fast_desc *desc)
>> Use a better name please.
>>
>
> I'll try to think something up. All these two functions do is convert a
> struct can_frame to the appropriate structure for the firmware, and
> back. How about "janz_convert_tocan() and janz_convert_fromcan()"?
can_frame_to_janz and janz_to_can_frame would already be fine. "can" is
to general.
[snip]
>>> +
>>> + cf->can_id |= idflags;
>>> + cf->data[1] = d1;
>> Hm, the data field to be used depends on the error type.
>>
>
> This code is copied from esd_pci331.c. If I don't have a good example,
> how can I be expected to do things correctly!
>
> How do I find out exactly which field belongs to which data type?
See include/linux/can/error.h
>>> +
>>> + netif_rx(skb);
>>> +
>>> + stats->rx_packets++;
>>> + stats->rx_bytes += cf->can_dlc;
>>> + return 0;
>>> +}
[snip]
>>> + rxerr = msg->data[4];
>>> + txerr = msg->data[5];
>> Should go to field 6 and 7.
>>
>
> You're confused. These come from the firmware, they are not going into a
> struct can_frame. These are the buffer locations in the message sent by
> the firmware for rx/tx error counter registers.
Right. Sorry for the noise.
>>> +
>>> + /* state is error-active by default */
>>> + state = CAN_STATE_ERROR_ACTIVE;
>>> +
>>> + if (rxerr >= 96 || txerr >= 96)
>>> + state = CAN_STATE_ERROR_WARNING;
>>> +
>>> + if (rxerr >= 128 || txerr >= 128)
>>> + state = CAN_STATE_ERROR_PASSIVE;
>>> +
>>> + if (rxerr >= 255 || txerr >= 255)
>>> + state = CAN_STATE_BUS_OFF;
>> You could use "else if" if you revert the order.
>
> Ok, I'll try that in the next version.
>
>> Also, 255 does not yet
>> mean bus-error, strictly speaking. Have you seen the device going bus-off?
>>
>
> Well, these are byte-sized registers. They can never exceed 255 (0xff),
> they would exceed their bit-width. What *should* I do here?
>
> I don't think I've seen the device go bus-off. How would I cause that
> situation?
Short-circuit the CAN low and high wires and send a message. Do you get
any notification?
>>> +
>>> + /* check if we should generate an error frame at all */
>>> + if (state == mod->can.state || mod->can.state == CAN_STATE_STOPPED) {
>>> + dev_dbg(mod->dev, "no error frame needed: state %d\n", state);
>>> + return;
>>> + }
>> Shouldn't this check be done first?
>>
>
> The variable "state" isn't set then. This code is basically copied from
> esd_pci331.c, but I moved the checking of priv->can.state out of each
> 'case', into one place.
>
>>> + dev_dbg(mod->dev, "state change: state %d\n", state);
>>> + mod->can.state = state;
>>> +
>>> + if (state == CAN_STATE_BUS_OFF) {
>>> + janz_err_frame(mod, CAN_ERR_BUSOFF, 0);
>>> + return;
>>> + }
>>> +
>>> + if (state == CAN_STATE_ERROR_PASSIVE) {
>>> + err = (rxerr >= 128) ? CAN_ERR_CRTL_RX_PASSIVE
>>> + : CAN_ERR_CRTL_TX_PASSIVE;
>>> + janz_err_frame(mod, CAN_ERR_CRTL, err);
>>> + return;
>>> + }
>>> +
>>> + if (state == CAN_STATE_ERROR_WARNING) {
>>> + err = (rxerr >= 96) ? CAN_ERR_CRTL_RX_WARNING
>>> + : CAN_ERR_CRTL_TX_WARNING;
>>> + janz_err_frame(mod, CAN_ERR_CRTL, err);
>>> + return;
>>> + }
>> If you use "else if" as suggested, the code could be shortened a lot, I
>> think (by doing everything within the if/else block).
>>
>> Just for curiosity, what does "candump -t d any,0:0,#FFFFFFFF" report
>> when you trigger a bus-error or when you send a message with no cable
>> connected.
>>
>
> Nothing. The device just eventually runs out of send buffers when no
> cable is connected. It doesn't send any error messages.
Hm, if you do not get any notification this code is useless.
>>> + /* nothing needed for error-active state */
>>> +}
>>> +
>>> +static void janz_handle_unknown(struct janz_ican3 *mod, struct janz_msg
>>> *msg)
>> Handle what?
>>
>
> The firmware has about 50 different messages it can send to the driver.
> I only handled the few that we expect to see. I put this in place so we
> get a log of message types that the driver doesn't handle yet.
>
> Should I remove it, and just drop all messages we don't handle without
> printing anything? Seems like a hindrance to debugging problems.
I have just a problem with the name, which is not specific enough. A
better name would be "janz_handle_unknown_message".
[snip]
>>> + switch (msg->spec) {
>>> + case MSG_IDVERS:
>>> + janz_handle_idvers(mod, msg);
>>> + break;
>>> + case MSG_MSGLOST:
>>> + case MSG_FMSGLOST:
>>> + janz_handle_msglost(mod, msg);
>>> + break;
>> You shoud create error messages for msglost as well.
>>
>
> Ok. What kind of messages? This message means that the driver is not
> reading CAN frames fast enough, and the firmware ran out of locations to
> store them. It is exactly the same as this driver's xmit() routine
> running out of buffers to place CAN messages for sending.
CAN_ERR_CRTL_RX_OVERFLOW and CAN_ERR_CRTL_RX_OVERFLOW from
http://lxr.linux.no/#linux+v2.6.32/include/linux/can/error.h.
[snip]
>>> + /* write back the control bits with IVALID unset */
>>> + control &= ~DESC_IVALID;
>>> + iowrite8(control, addr);
>> This seems to be duplicated code. Here a helper function would make
>> sense in contrast to your *one* line functions, e.g. to enable the
>> interrupts, which just increases code size.
>>
>
> The one-liners are marked inline, so they should get compiled to
> io(read|write)8(), without any function call overhead. I used them
> because their *names* are descriptive.
You do that in a few cases but in many other you use ioread8() directly.
I'm not worried about overhead.
> It is much easier to tell that this clears interrupts:
> janz_clr_int(mod);
>
> Than this:
> ioread8(mod->regs + DPM_REG_INT);
>
> Don't you think?
/* Clear interrupt */
ioread8(mod->regs + DPM_REG_INT);
does make pretty clear what the call does and I do not need to lookup
how it's implemented. If the interrupt is cleared in more than one place
or if it's a complex action, a function is useful, of course.
> I'm not sure how to clearly function-ize the clearing of the IVALID bit
> in descriptors, but I'll try for the next version.
Yes, a set of functions would be handy, I think.
[snip]
>>> + /* bring the bus online */
>>> + ret = janz_set_bus_state(mod, true);
>>> + if (ret) {
>>> + dev_err(mod->dev, "unable to set bus-on\n");
>>> + return ret;
>>> + }
>> How is bus-off recovery supposed to work? In general, if the card/hw
>> recovery automatically, we use the following procedure:
>>
>> restart_ms == 0: the device should be *stopped* on bus-off allowing
>> to user/app to restart it manually using this function.
>>
>> restart_ms > 0: the device is allowed to recover from bus-off
>> automatically.
>>
>> Could that be implemented?
>>
>
> The datasheet doesn't mention the word "restart" or "recover". I guess
> it doesn't recover automatically. Again, this code was copied from the
> esd_pci331.c driver. Is that driver's error recovery broken? What should
> I be doing here?
Makes sense as the SJA1000 does not recover automatically. But then some
kind of notification should be send otherwise the app does not known
what's going on.
>>> + /* disable our IRQ, then hookup the IRQ handler */
>>> + janz_disable_interrupts(mod);
>>> + ret = request_irq(mod->irq, janz_irq, IRQF_SHARED, DRV_NAME, mod);
>>> + if (ret) {
>>> + dev_err(dev, "unable to request IRQ\n");
>>> + goto out_iounmap_ctrl;
>>> + }
>> Is this interrupt exclisively for CAN? ... or do you need a dispatcher
>> in the MODULbus driver?
>>
>
> The interrupt is a function of the PCI bridge chip on the CMOD-IO
> carrier board. However, it uses a "write-1 to enable" and "write-1 to
> disable" interface, meaning each MODULbus module can have their own
> interrupt handler. The interrupt handler must check that its module is
> interrupting, just like any handler on a shared IRQ line.
>
> I don't need a dispatcher, but each module does need to know it's module
> number. See the janz_irq() function, and notice how I use a bitwise and
> with (1 << mod->num) to determine if this module is interrupting.
>
> AFAIK, Linux always calls all interrupt handlers attached to a shared
> interrupt line.
OK, that's fine.
Wolfgang.
_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core