123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- /*
- * Copyright (C) 2008-2010
- *
- * - Kurt Van Dijck, EIA Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
- #include <linux/firmware.h>
- #include <linux/sched.h>
- #include <asm/div64.h>
- #include <asm/io.h>
- #include "softing.h"
- /*
- * low level DPRAM command.
- * Make sure that card->dpram[DPRAM_FCT_HOST] is preset
- */
- static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
- const char *msg)
- {
- int ret;
- unsigned long stamp;
- iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
- iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
- iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
- /* be sure to flush this to the card */
- wmb();
- stamp = jiffies + 1 * HZ;
- /* wait for card */
- do {
- /* DPRAM_FCT_HOST is _not_ aligned */
- ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
- (ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
- /* don't have any cached variables */
- rmb();
- if (ret == RES_OK)
- /* read return-value now */
- return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
- if ((ret != vector) || time_after(jiffies, stamp))
- break;
- /* process context => relax */
- usleep_range(500, 10000);
- } while (1);
- ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
- dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
- return ret;
- }
- static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
- {
- int ret;
- ret = _softing_fct_cmd(card, cmd, 0, msg);
- if (ret > 0) {
- dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
- ret = -EIO;
- }
- return ret;
- }
- int softing_bootloader_command(struct softing *card, int16_t cmd,
- const char *msg)
- {
- int ret;
- unsigned long stamp;
- iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
- iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
- /* be sure to flush this to the card */
- wmb();
- stamp = jiffies + 3 * HZ;
- /* wait for card */
- do {
- ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
- /* don't have any cached variables */
- rmb();
- if (ret == RES_OK)
- return 0;
- if (time_after(jiffies, stamp))
- break;
- /* process context => relax */
- usleep_range(500, 10000);
- } while (!signal_pending(current));
- ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
- dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
- return ret;
- }
- static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
- uint16_t *plen, const uint8_t **pdat)
- {
- uint16_t checksum[2];
- const uint8_t *mem;
- const uint8_t *end;
- /*
- * firmware records are a binary, unaligned stream composed of:
- * uint16_t type;
- * uint32_t addr;
- * uint16_t len;
- * uint8_t dat[len];
- * uint16_t checksum;
- * all values in little endian.
- * We could define a struct for this, with __attribute__((packed)),
- * but would that solve the alignment in _all_ cases (cfr. the
- * struct itself may be an odd address)?
- *
- * I chose to use leXX_to_cpup() since this solves both
- * endianness & alignment.
- */
- mem = *pmem;
- *ptype = le16_to_cpup((void *)&mem[0]);
- *paddr = le32_to_cpup((void *)&mem[2]);
- *plen = le16_to_cpup((void *)&mem[6]);
- *pdat = &mem[8];
- /* verify checksum */
- end = &mem[8 + *plen];
- checksum[0] = le16_to_cpup((void *)end);
- for (checksum[1] = 0; mem < end; ++mem)
- checksum[1] += *mem;
- if (checksum[0] != checksum[1])
- return -EINVAL;
- /* increment */
- *pmem += 10 + *plen;
- return 0;
- }
- int softing_load_fw(const char *file, struct softing *card,
- __iomem uint8_t *dpram, unsigned int size, int offset)
- {
- const struct firmware *fw;
- int ret;
- const uint8_t *mem, *end, *dat;
- uint16_t type, len;
- uint32_t addr;
- uint8_t *buf = NULL, *new_buf;
- int buflen = 0;
- int8_t type_end = 0;
- ret = reject_firmware(&fw, file, &card->pdev->dev);
- if (ret < 0)
- return ret;
- dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
- ", offset %c0x%04x\n",
- card->pdat->name, file, (unsigned int)fw->size,
- (offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
- /* parse the firmware */
- mem = fw->data;
- end = &mem[fw->size];
- /* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
- if (ret < 0)
- goto failed;
- if (type != 0xffff)
- goto failed;
- if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
- ret = -EINVAL;
- goto failed;
- }
- /* ok, we had a header */
- while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
- if (ret < 0)
- goto failed;
- if (type == 3) {
- /* start address, not used here */
- continue;
- } else if (type == 1) {
- /* eof */
- type_end = 1;
- break;
- } else if (type != 0) {
- ret = -EINVAL;
- goto failed;
- }
- if ((addr + len + offset) > size)
- goto failed;
- memcpy_toio(&dpram[addr + offset], dat, len);
- /* be sure to flush caches from IO space */
- mb();
- if (len > buflen) {
- /* align buflen */
- buflen = (len + (1024-1)) & ~(1024-1);
- new_buf = krealloc(buf, buflen, GFP_KERNEL);
- if (!new_buf) {
- ret = -ENOMEM;
- goto failed;
- }
- buf = new_buf;
- }
- /* verify record data */
- memcpy_fromio(buf, &dpram[addr + offset], len);
- if (memcmp(buf, dat, len)) {
- /* is not ok */
- dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
- ret = -EIO;
- goto failed;
- }
- }
- if (!type_end)
- /* no end record seen */
- goto failed;
- ret = 0;
- failed:
- kfree(buf);
- release_firmware(fw);
- if (ret < 0)
- dev_info(&card->pdev->dev, "firmware %s failed\n", file);
- return ret;
- }
- int softing_load_app_fw(const char *file, struct softing *card)
- {
- const struct firmware *fw;
- const uint8_t *mem, *end, *dat;
- int ret, j;
- uint16_t type, len;
- uint32_t addr, start_addr = 0;
- unsigned int sum, rx_sum;
- int8_t type_end = 0, type_entrypoint = 0;
- ret = reject_firmware(&fw, file, &card->pdev->dev);
- if (ret) {
- dev_alert(&card->pdev->dev, "reject_firmware(%s) got %i\n",
- file, ret);
- return ret;
- }
- dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
- file, (unsigned long)fw->size);
- /* parse the firmware */
- mem = fw->data;
- end = &mem[fw->size];
- /* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
- if (ret)
- goto failed;
- ret = -EINVAL;
- if (type != 0xffff) {
- dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
- type);
- goto failed;
- }
- if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
- dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
- len, dat);
- goto failed;
- }
- /* ok, we had a header */
- while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
- if (ret)
- goto failed;
- if (type == 3) {
- /* start address */
- start_addr = addr;
- type_entrypoint = 1;
- continue;
- } else if (type == 1) {
- /* eof */
- type_end = 1;
- break;
- } else if (type != 0) {
- dev_alert(&card->pdev->dev,
- "unknown record type 0x%04x\n", type);
- ret = -EINVAL;
- goto failed;
- }
- /* regualar data */
- for (sum = 0, j = 0; j < len; ++j)
- sum += dat[j];
- /* work in 16bit (target) */
- sum &= 0xffff;
- memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
- iowrite32(card->pdat->app.offs + card->pdat->app.addr,
- &card->dpram[DPRAM_COMMAND + 2]);
- iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
- iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
- iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
- ret = softing_bootloader_command(card, 1, "loading app.");
- if (ret < 0)
- goto failed;
- /* verify checksum */
- rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
- if (rx_sum != sum) {
- dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
- ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
- ret = -EIO;
- goto failed;
- }
- }
- if (!type_end || !type_entrypoint)
- goto failed;
- /* start application in card */
- iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
- iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
- ret = softing_bootloader_command(card, 3, "start app.");
- if (ret < 0)
- goto failed;
- ret = 0;
- failed:
- release_firmware(fw);
- if (ret < 0)
- dev_info(&card->pdev->dev, "firmware %s failed\n", file);
- return ret;
- }
- static int softing_reset_chip(struct softing *card)
- {
- int ret;
- do {
- /* reset chip */
- iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
- iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
- iowrite8(1, &card->dpram[DPRAM_RESET]);
- iowrite8(0, &card->dpram[DPRAM_RESET+1]);
- ret = softing_fct_cmd(card, 0, "reset_can");
- if (!ret)
- break;
- if (signal_pending(current))
- /* don't wait any longer */
- break;
- } while (1);
- card->tx.pending = 0;
- return ret;
- }
- int softing_chip_poweron(struct softing *card)
- {
- int ret;
- /* sync */
- ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
- if (ret < 0)
- goto failed;
- ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
- if (ret < 0)
- goto failed;
- ret = softing_reset_chip(card);
- if (ret < 0)
- goto failed;
- /* get_serial */
- ret = softing_fct_cmd(card, 43, "get_serial_number");
- if (ret < 0)
- goto failed;
- card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
- /* get_version */
- ret = softing_fct_cmd(card, 12, "get_version");
- if (ret < 0)
- goto failed;
- card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
- card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
- card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
- card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
- card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
- return 0;
- failed:
- return ret;
- }
- static void softing_initialize_timestamp(struct softing *card)
- {
- uint64_t ovf;
- card->ts_ref = ktime_get();
- /* 16MHz is the reference */
- ovf = 0x100000000ULL * 16;
- do_div(ovf, card->pdat->freq ?: 16);
- card->ts_overflow = ktime_add_us(ktime_set(0, 0), ovf);
- }
- ktime_t softing_raw2ktime(struct softing *card, u32 raw)
- {
- uint64_t rawl;
- ktime_t now, real_offset;
- ktime_t target;
- ktime_t tmp;
- now = ktime_get();
- real_offset = ktime_sub(ktime_get_real(), now);
- /* find nsec from card */
- rawl = raw * 16;
- do_div(rawl, card->pdat->freq ?: 16);
- target = ktime_add_us(card->ts_ref, rawl);
- /* test for overflows */
- tmp = ktime_add(target, card->ts_overflow);
- while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
- card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
- target = tmp;
- tmp = ktime_add(target, card->ts_overflow);
- }
- return ktime_add(target, real_offset);
- }
- static inline int softing_error_reporting(struct net_device *netdev)
- {
- struct softing_priv *priv = netdev_priv(netdev);
- return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- ? 1 : 0;
- }
- int softing_startstop(struct net_device *dev, int up)
- {
- int ret;
- struct softing *card;
- struct softing_priv *priv;
- struct net_device *netdev;
- int bus_bitmask_start;
- int j, error_reporting;
- struct can_frame msg;
- const struct can_bittiming *bt;
- priv = netdev_priv(dev);
- card = priv->card;
- if (!card->fw.up)
- return -EIO;
- ret = mutex_lock_interruptible(&card->fw.lock);
- if (ret)
- return ret;
- bus_bitmask_start = 0;
- if (dev && up)
- /* prepare to start this bus as well */
- bus_bitmask_start |= (1 << priv->index);
- /* bring netdevs down */
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- netdev = card->net[j];
- if (!netdev)
- continue;
- priv = netdev_priv(netdev);
- if (dev != netdev)
- netif_stop_queue(netdev);
- if (netif_running(netdev)) {
- if (dev != netdev)
- bus_bitmask_start |= (1 << j);
- priv->tx.pending = 0;
- priv->tx.echo_put = 0;
- priv->tx.echo_get = 0;
- /*
- * this bus' may just have called open_candev()
- * which is rather stupid to call close_candev()
- * already
- * but we may come here from busoff recovery too
- * in which case the echo_skb _needs_ flushing too.
- * just be sure to call open_candev() again
- */
- close_candev(netdev);
- }
- priv->can.state = CAN_STATE_STOPPED;
- }
- card->tx.pending = 0;
- softing_enable_irq(card, 0);
- ret = softing_reset_chip(card);
- if (ret)
- goto failed;
- if (!bus_bitmask_start)
- /* no busses to be brought up */
- goto card_done;
- if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
- && (softing_error_reporting(card->net[0])
- != softing_error_reporting(card->net[1]))) {
- dev_alert(&card->pdev->dev,
- "err_reporting flag differs for busses\n");
- goto invalid;
- }
- error_reporting = 0;
- if (bus_bitmask_start & 1) {
- netdev = card->net[0];
- priv = netdev_priv(netdev);
- error_reporting += softing_error_reporting(netdev);
- /* init chip 1 */
- bt = &priv->can.bittiming;
- iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(bt->phase_seg1 + bt->prop_seg,
- &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
- &card->dpram[DPRAM_FCT_PARAM + 10]);
- ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
- if (ret < 0)
- goto failed;
- /* set mode */
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
- ret = softing_fct_cmd(card, 3, "set_mode[0]");
- if (ret < 0)
- goto failed;
- /* set filter */
- /* 11bit id & mask */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
- /* 29bit id.lo & mask.lo & id.hi & mask.hi */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
- ret = softing_fct_cmd(card, 7, "set_filter[0]");
- if (ret < 0)
- goto failed;
- /* set output control */
- iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
- ret = softing_fct_cmd(card, 5, "set_output[0]");
- if (ret < 0)
- goto failed;
- }
- if (bus_bitmask_start & 2) {
- netdev = card->net[1];
- priv = netdev_priv(netdev);
- error_reporting += softing_error_reporting(netdev);
- /* init chip2 */
- bt = &priv->can.bittiming;
- iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(bt->phase_seg1 + bt->prop_seg,
- &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
- &card->dpram[DPRAM_FCT_PARAM + 10]);
- ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
- if (ret < 0)
- goto failed;
- /* set mode2 */
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
- ret = softing_fct_cmd(card, 4, "set_mode[1]");
- if (ret < 0)
- goto failed;
- /* set filter2 */
- /* 11bit id & mask */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
- /* 29bit id.lo & mask.lo & id.hi & mask.hi */
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
- ret = softing_fct_cmd(card, 8, "set_filter[1]");
- if (ret < 0)
- goto failed;
- /* set output control2 */
- iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
- ret = softing_fct_cmd(card, 6, "set_output[1]");
- if (ret < 0)
- goto failed;
- }
- /* enable_error_frame */
- /*
- * Error reporting is switched off at the moment since
- * the receiving of them is not yet 100% verified
- * This should be enabled sooner or later
- *
- if (error_reporting) {
- ret = softing_fct_cmd(card, 51, "enable_error_frame");
- if (ret < 0)
- goto failed;
- }
- */
- /* initialize interface */
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
- iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
- ret = softing_fct_cmd(card, 17, "initialize_interface");
- if (ret < 0)
- goto failed;
- /* enable_fifo */
- ret = softing_fct_cmd(card, 36, "enable_fifo");
- if (ret < 0)
- goto failed;
- /* enable fifo tx ack */
- ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
- if (ret < 0)
- goto failed;
- /* enable fifo tx ack2 */
- ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
- if (ret < 0)
- goto failed;
- /* start_chip */
- ret = softing_fct_cmd(card, 11, "start_chip");
- if (ret < 0)
- goto failed;
- iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
- iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
- if (card->pdat->generation < 2) {
- iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
- /* flush the DPRAM caches */
- wmb();
- }
- softing_initialize_timestamp(card);
- /*
- * do socketcan notifications/status changes
- * from here, no errors should occur, or the failed: part
- * must be reviewed
- */
- memset(&msg, 0, sizeof(msg));
- msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
- msg.can_dlc = CAN_ERR_DLC;
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- if (!(bus_bitmask_start & (1 << j)))
- continue;
- netdev = card->net[j];
- if (!netdev)
- continue;
- priv = netdev_priv(netdev);
- priv->can.state = CAN_STATE_ERROR_ACTIVE;
- open_candev(netdev);
- if (dev != netdev) {
- /* notify other busses on the restart */
- softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
- ++priv->can.can_stats.restarts;
- }
- netif_wake_queue(netdev);
- }
- /* enable interrupts */
- ret = softing_enable_irq(card, 1);
- if (ret)
- goto failed;
- card_done:
- mutex_unlock(&card->fw.lock);
- return 0;
- invalid:
- ret = -EINVAL;
- failed:
- softing_enable_irq(card, 0);
- softing_reset_chip(card);
- mutex_unlock(&card->fw.lock);
- /* bring all other interfaces down */
- for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
- netdev = card->net[j];
- if (!netdev)
- continue;
- dev_close(netdev);
- }
- return ret;
- }
- int softing_default_output(struct net_device *netdev)
- {
- struct softing_priv *priv = netdev_priv(netdev);
- struct softing *card = priv->card;
- switch (priv->chip) {
- case 1000:
- return (card->pdat->generation < 2) ? 0xfb : 0xfa;
- case 5:
- return 0x60;
- default:
- return 0x40;
- }
- }
|