/* GRCAN private data structure */ struct grcan_priv { struct can_priv can; /* must be the first member */ struct net_device *dev; struct device *ofdev_dev; struct napi_struct napi;
struct sk_buff **echo_skb; /* We allocate this on our own */
/* The echo skb pointer, pointing into echo_skb and indicating which *framescanbeechoedback.Seethe"Notesonthetxcyclicbuffer *handling"-commentforgrcan_start_xmitformoredetails.
*/
u32 eskbp;
/* Lock for controlling changes to the netif tx queue state, accesses to *theecho_skbpointereskbpandformakingsurethatarunningreset *and/oracloseoftheinterfaceisdonewithoutinterferencefrom *otherpartsofthecode. * *Theecho_skbpointer,eskbp,shouldonlybeaccessedunderthislock *asitcanbechangedinseveralplacesandtogetherwithdecisionson *whethertowakeupthetxqueue. * *Thetxqueuemustneverbewokenupifthereisarunningresetor *closeinprogress. * *Arunningreset(seebelowonneed_txbug_workaround)shouldneverbe *doneiftheinterfaceisclosingdownandseveralrunningresets *shouldneverbescheduledsimultaneously.
*/
spinlock_t lock;
/* Whether a workaround is needed due to a bug in older hardware. In *thiscase,thedriverbothtriestopreventthebugfrombeing *triggeredandrecovers,ifthebugneverthelesshappens,bydoinga *runningreset.Arunningreset,resetsthedeviceandcontinuesfrom *whereitwerewithoutbeingnoticeablefromoutsidethedriver(apart *fromslightdelays).
*/ bool need_txbug_workaround;
/* To trigger initization of running reset and to trigger running reset *respectivelyinthecaseofahangeddeviceduetoatxbug.
*/ struct timer_list hang_timer; struct timer_list rr_timer;
/* To avoid waking up the netif queue and restarting timers *whenaresetisscheduledorwhenclosingofthedeviceis *undergoing
*/ bool resetting; bool closing;
};
/* Wait time for a short wait for ongoing to clear */ #define GRCAN_SHORTWAIT_USECS 10
/* Limit on the number of transmitted bits of an eff frame according to the CAN *specification:1bitstartofframe,32bitsarbitrationfield,6bits *controlfield,8bytesdatafield,16bitscrcfield,2bitsACKfieldand7 *bitsendofframe
*/ #define GRCAN_EFF_FRAME_MAX_BITS (1+32+6+8*8+16+2+7)
/* a and b should both be in [0,size] and a == b == size should not hold */ staticinline u32 grcan_ring_add(u32 a, u32 b, u32 size)
{
u32 sum = a + b;
if (sum < size) return sum; else return sum - size;
}
/* a and b should both be in [0,size) */ staticinline u32 grcan_ring_sub(u32 a, u32 b, u32 size)
{ return grcan_ring_add(a, size - b, size);
}
/* Available slots for new transmissions */ staticinline u32 grcan_txspace(size_t txsize, u32 txwr, u32 eskbp)
{
u32 slots = txsize / GRCAN_MSG_SIZE - 1;
u32 used = grcan_ring_sub(txwr, eskbp, txsize) / GRCAN_MSG_SIZE;
return slots - used;
}
/* Configuration parameters that can be set via module parameters */ staticstruct grcan_device_config grcan_module_config =
GRCAN_DEFAULT_DEVICE_CONFIG;
/* Let priv->eskbp catch up to regs->txrd and echo back the skbs if echo *istrueandfreethemotherwise. * *Ifbudgetis>=0,stopafterhandlingatmostbudgetskbs.Otherwise, *continueuntilpriv->eskbpcatchesuptoregs->txrd. * *priv->lock*must*beheldwhencallingthisfunction
*/ staticint catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
{ struct grcan_priv *priv = netdev_priv(dev); struct grcan_registers __iomem *regs = priv->regs; struct grcan_dma *dma = &priv->dma; struct net_device_stats *stats = &dev->stats; int i, work_done;
/* Updates to priv->eskbp and wake-ups of the queue needs to *beatomictowardsthereadsofpriv->eskbpandshut-downs *ofthequeueingrcan_start_xmit.
*/
u32 txrd = grcan_read_reg(®s->txrd);
for (work_done = 0; work_done < budget || budget < 0; work_done++) { if (priv->eskbp == txrd) break;
i = priv->eskbp / GRCAN_MSG_SIZE; if (echo) { /* Normal echo of messages */
stats->tx_packets++;
stats->tx_bytes += can_get_echo_skb(dev, i, NULL);
} else { /* For cleanup of untransmitted messages */
can_free_echo_skb(dev, i, NULL);
}
if (unlikely(grcan_read_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE))) { /* Should never happen */
netdev_err(dev, "TXCTRL enabled at TXLOSS in one shot mode\n");
} else { /* By the time an GRCAN_IRQ_TXLOSS is generated in *one-shotmodethereisnoprobleminwriting *toTXRDeveninversionsofthehardwarein *whichGRCAN_TXCTRL_ONGOINGisnotclearedproperly *inone-shotmode.
*/
/* Zero potential error_frame */
memset(&cf, 0, sizeof(cf));
/* Message lost interrupt. This might be due to arbitration error, but *isalsotriggeredwhenthereisnooneelseonthecanbusorwhen *thereisaproblemwiththehardwareinterfaceorthebusitself.As *arbitrationerrorscannotbesingledout,noerrorframesare *generatedreportingthiseventasanarbitrationerror.
*/ if (sources & GRCAN_IRQ_TXLOSS) { /* Take care of failed one-shot transmit */ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
grcan_lost_one_shot_frame(dev);
/* Stop printing as soon as error passive or bus off is in *effecttolimittheamountoftxlossdebugprintouts.
*/ if (!(status & GRCAN_STAT_ERRCTR_RELATED)) {
netdev_dbg(dev, "tx message lost\n");
stats->tx_errors++;
}
}
/* Conditions dealing with the error counters. There is no interrupt for *errorwarning,butthereareinterruptsforincreasesoftheerror *counters.
*/ if ((sources & GRCAN_IRQ_ERRCTR_RELATED) ||
(status & GRCAN_STAT_ERRCTR_RELATED)) { enum can_state state = priv->can.state; enum can_state oldstate = state;
u32 txerr = (status & GRCAN_STAT_TXERRCNT)
>> GRCAN_STAT_TXERRCNT_BIT;
u32 rxerr = (status & GRCAN_STAT_RXERRCNT)
>> GRCAN_STAT_RXERRCNT_BIT;
/* Figure out current state */ if (status & GRCAN_STAT_OFF) {
state = CAN_STATE_BUS_OFF;
} elseif (status & GRCAN_STAT_PASS) {
state = CAN_STATE_ERROR_PASSIVE;
} elseif (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT ||
rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT) {
state = CAN_STATE_ERROR_WARNING;
} else {
state = CAN_STATE_ERROR_ACTIVE;
}
/* Handle and report state changes */ if (state != oldstate) { switch (state) { case CAN_STATE_BUS_OFF:
netdev_dbg(dev, "bus-off\n");
netif_carrier_off(dev);
priv->can.can_stats.bus_off++;
/* Prevent the hardware from recovering from bus *offonitsownifrestartisdisabled.
*/ if (!priv->can.restart_ms)
grcan_stop_hardware(dev);
cf.can_id |= CAN_ERR_BUSOFF; break;
case CAN_STATE_ERROR_PASSIVE:
netdev_dbg(dev, "Error passive condition\n");
priv->can.can_stats.error_passive++;
cf.can_id |= CAN_ERR_CRTL; if (txerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT)
cf.data[1] |= CAN_ERR_CRTL_TX_PASSIVE; if (rxerr >= GRCAN_STAT_ERRCNT_PASSIVE_LIMIT)
cf.data[1] |= CAN_ERR_CRTL_RX_PASSIVE; break;
case CAN_STATE_ERROR_WARNING:
netdev_dbg(dev, "Error warning condition\n");
priv->can.can_stats.error_warning++;
cf.can_id |= CAN_ERR_CRTL; if (txerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT)
cf.data[1] |= CAN_ERR_CRTL_TX_WARNING; if (rxerr >= GRCAN_STAT_ERRCNT_WARNING_LIMIT)
cf.data[1] |= CAN_ERR_CRTL_RX_WARNING; break;
case CAN_STATE_ERROR_ACTIVE:
netdev_dbg(dev, "Error active condition\n");
cf.can_id |= CAN_ERR_CRTL; break;
default: /* There are no others at this point */ break;
}
cf.can_id |= CAN_ERR_CNT;
cf.data[6] = txerr;
cf.data[7] = rxerr;
priv->can.state = state;
}
/* Prevent anything to be enabled again and halt device */
priv->closing = true;
netif_stop_queue(dev);
grcan_stop_hardware(dev);
priv->can.state = CAN_STATE_STOPPED;
spin_unlock_irqrestore(&priv->lock, flags);
}
/* Pass on error frame if something to report, *i.e.idcontainssomeinformation
*/ if (cf.can_id) { struct can_frame *skb_cf; struct sk_buff *skb = alloc_can_err_skb(dev, &skb_cf);
if (skb == NULL) {
netdev_dbg(dev, "could not allocate error frame\n"); return;
}
skb_cf->can_id |= cf.can_id;
memcpy(skb_cf->data, cf.data, sizeof(cf.data));
/* Find out the source */
sources = grcan_read_reg(®s->pimsr); if (!sources) return IRQ_NONE;
grcan_write_reg(®s->picr, sources);
status = grcan_read_reg(®s->stat);
/* If we got TX progress, the device has not hanged, *sodisablethehangtimer
*/ if (priv->need_txbug_workaround &&
(sources & (GRCAN_IRQ_TX | GRCAN_IRQ_TXLOSS))) {
timer_delete(&priv->hang_timer);
}
/* Frame(s) received or transmitted */ if (sources & (GRCAN_IRQ_TX | GRCAN_IRQ_RX)) { /* Disable tx/rx interrupts and schedule poll(). No need for *lockingasinterferencefromarunningresetatworstleads *toanextrainterrupt.
*/
grcan_clear_bits(®s->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX);
napi_schedule(&priv->napi);
}
/* (Potential) error conditions to take care of */ if (sources & GRCAN_IRQ_ERRORS)
grcan_err(dev, sources, status);
return IRQ_HANDLED;
}
/* Reset device and restart operations from where they were. * *ThisassumesthatRXCTRL&RXCTRLisproperlydisabledandthatRX *isnotONGOING(TXmightbestuckinONGOINGduetoaharwrwarebug *forsingleshot)
*/ staticvoid grcan_running_reset(struct timer_list *t)
{ struct grcan_priv *priv = timer_container_of(priv, t, rr_timer); struct net_device *dev = priv->dev; struct grcan_registers __iomem *regs = priv->regs; unsignedlong flags;
/* This temporarily messes with eskbp, so we need to lock *priv->lock
*/
spin_lock_irqsave(&priv->lock, flags);
/* Start queue if there is size and listen-onle mode is not *enabled
*/ if (grcan_txspace(priv->dma.tx.size, txwr, priv->eskbp) &&
!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
netif_wake_queue(dev);
}
spin_unlock_irqrestore(&priv->lock, flags);
netdev_err(dev, "Device reset and restored\n");
}
/* Waiting time in usecs corresponding to the transmission of three maximum *sizedcanframesinthegivenbitrate(inbits/sec).Waitingforthisamount *oftimemakessurethatthecancontrollerhavetimetofinishsendingor *receivingaframewithagoodmargin. * *usecs/sec*numberofframes*bits/frame/bits/sec
*/ staticinline u32 grcan_ongoing_wait_usecs(__u32 bitrate)
{ return1000000 * 3 * GRCAN_EFF_FRAME_MAX_BITS / bitrate;
}
/* Set timer so that it will not fire until after a period in which the can *controllerhaveagoodmargintofinishtransmittingaframeunlessithas *hanged
*/ staticinlinevoid grcan_reset_timer(struct timer_list *timer, __u32 bitrate)
{
u32 wait_jiffies = usecs_to_jiffies(grcan_ongoing_wait_usecs(bitrate));
/* The main body of this function must never be executed again *untilafteranexecutionofgrcan_running_reset
*/ if (!priv->resetting && !priv->closing) {
priv->resetting = true;
netif_stop_queue(dev);
grcan_clear_bits(®s->txctrl, GRCAN_TXCTRL_ENABLE);
grcan_clear_bits(®s->rxctrl, GRCAN_RXCTRL_ENABLE);
grcan_reset_timer(&priv->rr_timer, priv->can.bittiming.bitrate);
}
/* Need a whole number of GRCAN_BUFFER_ALIGNMENT for the large, *i.e.firstbuffer
*/
size_t maxs = max(tsize, rsize);
size_t lsize = ALIGN(maxs, GRCAN_BUFFER_ALIGNMENT);
/* Put the small buffer after that */
size_t ssize = min(tsize, rsize);
/* Extra GRCAN_BUFFER_ALIGNMENT to allow for alignment */
dma->base_size = lsize + ssize + GRCAN_BUFFER_ALIGNMENT;
dma->base_buf = dma_alloc_coherent(priv->ofdev_dev,
dma->base_size,
&dma->base_handle,
GFP_KERNEL);
/* priv->lock *must* be held when calling this function */ staticint grcan_start(struct net_device *dev)
{ struct grcan_priv *priv = netdev_priv(dev); struct grcan_registers __iomem *regs = priv->regs;
u32 confop, txctrl;
grcan_reset(dev);
grcan_write_reg(®s->txaddr, priv->dma.tx.handle);
grcan_write_reg(®s->txsize, priv->dma.tx.size); /* regs->txwr, regs->txrd and priv->eskbp already set to 0 by reset */
grcan_write_reg(®s->rxaddr, priv->dma.rx.handle);
grcan_write_reg(®s->rxsize, priv->dma.rx.size); /* regs->rxwr and regs->rxrd already set to 0 by reset */
if (mode == CAN_MODE_START) { /* This might be called to restart the device to recover from *busofferrors
*/
spin_lock_irqsave(&priv->lock, flags); if (priv->closing || priv->resetting) {
err = -EBUSY;
} else {
netdev_info(dev, "Restarting device\n");
grcan_start(dev); if (!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
netif_wake_queue(dev);
}
spin_unlock_irqrestore(&priv->lock, flags); return err;
} return -EOPNOTSUPP;
}
work_done = catch_up_echo_skb(dev, -1, true); if (work_done) { if (!priv->resetting && !priv->closing &&
!(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
netif_wake_queue(dev);
/* With napi we don't get TX interrupts for a while, *sopreventarunningresetwhilecatchingup
*/ if (priv->need_txbug_workaround)
timer_delete(&priv->hang_timer);
}
/* Guarantee no interference with a running reset that otherwise *couldturnoffinterrupts.
*/
spin_lock_irqsave(&priv->lock, flags);
/* Enable tx and rx interrupts again. No need to check *priv->closingasnapi_disableingrcan_closeiswaitingfor *schedulednapicallstofinish.
*/
grcan_set_bits(®s->imr, GRCAN_IRQ_TX | GRCAN_IRQ_RX);
spin_unlock_irqrestore(&priv->lock, flags);
}
return work_done;
}
/* Work tx bug by waiting while for the risky situation to clear. If that fails, *dropaframeinone-shotmodeorindicateabusydeviceotherwise. * *Returns0onsuccessfulwait.Otherwiseitsets*netdev_tx_statustothe *valuethatshouldbereturnedbygrcan_start_xmitwhenabortingthexmit.
*/ staticint grcan_txbug_workaround(struct net_device *dev, struct sk_buff *skb,
u32 txwr, u32 oneshotmode,
netdev_tx_t *netdev_tx_status)
{ struct grcan_priv *priv = netdev_priv(dev); struct grcan_registers __iomem *regs = priv->regs; struct grcan_dma *dma = &priv->dma; int i; unsignedlong flags;
/* Wait a while for ongoing to be cleared or read pointer to catch up to *writepointer.Thelatterisneededduetoabuginolderversionsof *GRCANinwhichONGOINGisnotclearedproperlyone-shotmodewhena *transmissionfails.
*/ for (i = 0; i < GRCAN_SHORTWAIT_USECS; i++) {
udelay(1); if (!grcan_read_bits(®s->txctrl, GRCAN_TXCTRL_ONGOING) ||
grcan_read_reg(®s->txrd) == txwr) { return0;
}
}
/* Clean up, in case the situation was not resolved */
spin_lock_irqsave(&priv->lock, flags); if (!priv->resetting && !priv->closing) { /* Queue might have been stopped earlier in grcan_start_xmit */ if (grcan_txspace(dma->tx.size, txwr, priv->eskbp))
netif_wake_queue(dev); /* Set a timer to resolve a hanged tx controller */ if (!timer_pending(&priv->hang_timer))
grcan_reset_timer(&priv->hang_timer,
priv->can.bittiming.bitrate);
}
spin_unlock_irqrestore(&priv->lock, flags);
if (oneshotmode) { /* In one-shot mode we should never end up here because *thentheinterrupthandlerincreasestxrdonTXLOSS, *butitisconsistentwithone-shotmodetodropthe *frameinthiscase.
*/
kfree_skb(skb);
*netdev_tx_status = NETDEV_TX_OK;
} else { /* In normal mode the socket-can transmission queue get *tokeeptheframesothatitcanberetransmitted *later
*/
*netdev_tx_status = NETDEV_TX_BUSY;
} return -EBUSY;
}
if (can_dev_dropped_skb(dev, skb)) return NETDEV_TX_OK;
/* Trying to transmit in silent mode will generate error interrupts, but *thisshouldneverhappen-thequeueshouldnothavebeenstarted.
*/ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) return NETDEV_TX_BUSY;
/* Reads of priv->eskbp and shut-downs of the queue needs to *beatomictowardstheupdatestopriv->eskbpandwake-ups *ofthequeueintheinterrupthandler.
*/
spin_lock_irqsave(&priv->lock, flags);
txwr = grcan_read_reg(®s->txwr);
space = grcan_txspace(dma->tx.size, txwr, priv->eskbp);
spin_unlock_irqrestore(&priv->lock, flags); /* End of critical section*/
/* This should never happen. If circular buffer is full, the *netif_stop_queueshouldhavebeenstoppedalready.
*/ if (unlikely(!space)) {
netdev_err(dev, "No buffer space, but queue is non-stopped.\n"); return NETDEV_TX_BUSY;
}
/* Convert and write CAN message to DMA buffer */
eff = cf->can_id & CAN_EFF_FLAG;
rtr = cf->can_id & CAN_RTR_FLAG;
id = cf->can_id & (eff ? CAN_EFF_MASK : CAN_SFF_MASK);
dlc = cf->len; if (eff)
tmp = (id << GRCAN_MSG_EID_BIT) & GRCAN_MSG_EID; else
tmp = (id << GRCAN_MSG_BID_BIT) & GRCAN_MSG_BID;
slot[0] = (eff ? GRCAN_MSG_IDE : 0) | (rtr ? GRCAN_MSG_RTR : 0) | tmp;
/* Checking that channel has not been disabled. These cases *shouldneverhappen
*/
txctrl = grcan_read_reg(®s->txctrl); if (!(txctrl & GRCAN_TXCTRL_ENABLE))
netdev_err(dev, "tx channel spuriously disabled\n");
/* Bug workaround for old version of grcan where updating txwr *inthesameclockcycleasthecontrollerupdatestxrdto *thecurrenttxwrcouldhangthecancontroller
*/ if (priv->need_txbug_workaround) {
txrd = grcan_read_reg(®s->txrd); if (unlikely(grcan_ring_sub(txwr, txrd, dma->tx.size) == 1)) {
netdev_tx_t txstatus;
/* Prepare skb for echoing. This must be after the bug workaround above *asownershipoftheskbispassedonbycallingcan_put_echo_skb. *ReturningNETDEV_TX_BUSYoraccessingskborcfafteracallto *can_put_echo_skbwouldbeanerrorunlessothermeasuresare *taken.
*/
can_put_echo_skb(skb, dev, slotindex, 0);
/* Make sure everything is written before allowing hardware to *readfromthememory
*/
wmb();
/* The following configuration options are made available both via module *parametersandwritablesysfsfiles.SeethechapteraboutGRCANinthe *documentationfortheGRLIBVHDLlibraryforfurtherdetails.
*/
GRCAN_CONFIG_ATTR(enable0, "Configuration of physical interface 0. Determines\n" \ "the \"Enable 0\" bit of the configuration register.\n" \ "Format: 0 | 1\nDefault: 0\n");
GRCAN_CONFIG_ATTR(enable1, "Configuration of physical interface 1. Determines\n" \ "the \"Enable 1\" bit of the configuration register.\n" \ "Format: 0 | 1\nDefault: 0\n");
GRCAN_CONFIG_ATTR(select, "Select which physical interface to use.\n" \ "Format: 0 | 1\nDefault: 0\n");
/* The tx and rx buffer size configuration options are only available via module *parameters.
*/
GRCAN_MODULE_PARAM(txsize, uint, GRCAN_INVALID_BUFFER_SIZE, "Sets the size of the tx buffer.\n" \ "Format: <unsigned int> where (txsize & ~0x1fffc0) == 0\n" \ "Default: 1024\n");
GRCAN_MODULE_PARAM(rxsize, uint, GRCAN_INVALID_BUFFER_SIZE, "Sets the size of the rx buffer.\n" \ "Format: <unsigned int> where (size & ~0x1fffc0) == 0\n" \ "Default: 1024\n");
/* Function that makes sure that configuration done using *moduleparametersaresettovalidvalues
*/ staticvoid grcan_sanitize_module_config(struct platform_device *ofdev)
{
grcan_sanitize_enable0(ofdev);
grcan_sanitize_enable1(ofdev);
grcan_sanitize_select(ofdev);
grcan_sanitize_txsize(ofdev);
grcan_sanitize_rxsize(ofdev);
}
err = register_candev(dev); if (err) goto exit_free_candev;
platform_set_drvdata(ofdev, dev);
/* Reset device to allow bit-timing to be set. No need to call *grcan_resetatthisstage.Thatisdoneingrcan_open.
*/
grcan_write_reg(®s->ctrl, GRCAN_CTRL_RESET);
/* Compare GRLIB version number with the first that does not *havethetxbug(seestart_xmit)
*/
sysid_parent = of_find_node_by_path("/ambapp0"); if (sysid_parent) {
err = of_property_read_u32(sysid_parent, "systemid", &sysid); if (!err && ((sysid & GRLIB_VERSION_MASK) >=
GRCAN_TXBUG_SAFE_GRLIB_VERSION))
txbug = false;
of_node_put(sysid_parent);
}
err = of_property_read_u32(np, "freq", &ambafreq); if (err) {
dev_err(&ofdev->dev, "unable to fetch \"freq\" property\n"); goto exit_error;
}
base = devm_platform_ioremap_resource(ofdev, 0); if (IS_ERR(base)) {
err = PTR_ERR(base); goto exit_error;
}
irq = irq_of_parse_and_map(np, GRCAN_IRQIX_IRQ); if (!irq) {
dev_err(&ofdev->dev, "no irq found\n");
err = -ENODEV; goto exit_error;
}
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.