135e62ae8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
203fd3cf5SKurt Van Dijck /*
303fd3cf5SKurt Van Dijck * Copyright (C) 2008-2010
403fd3cf5SKurt Van Dijck *
503fd3cf5SKurt Van Dijck * - Kurt Van Dijck, EIA Electronics
603fd3cf5SKurt Van Dijck */
703fd3cf5SKurt Van Dijck
803fd3cf5SKurt Van Dijck #include <linux/firmware.h>
9174cd4b1SIngo Molnar #include <linux/sched/signal.h>
1003fd3cf5SKurt Van Dijck #include <asm/div64.h>
11b7f080cfSAlexey Dobriyan #include <asm/io.h>
1203fd3cf5SKurt Van Dijck
1303fd3cf5SKurt Van Dijck #include "softing.h"
1403fd3cf5SKurt Van Dijck
1503fd3cf5SKurt Van Dijck /*
1603fd3cf5SKurt Van Dijck * low level DPRAM command.
1703fd3cf5SKurt Van Dijck * Make sure that card->dpram[DPRAM_FCT_HOST] is preset
1803fd3cf5SKurt Van Dijck */
_softing_fct_cmd(struct softing * card,int16_t cmd,uint16_t vector,const char * msg)1903fd3cf5SKurt Van Dijck static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
2003fd3cf5SKurt Van Dijck const char *msg)
2103fd3cf5SKurt Van Dijck {
2203fd3cf5SKurt Van Dijck int ret;
2303fd3cf5SKurt Van Dijck unsigned long stamp;
2403fd3cf5SKurt Van Dijck
2503fd3cf5SKurt Van Dijck iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
2603fd3cf5SKurt Van Dijck iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
2703fd3cf5SKurt Van Dijck iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
2803fd3cf5SKurt Van Dijck /* be sure to flush this to the card */
2903fd3cf5SKurt Van Dijck wmb();
3003fd3cf5SKurt Van Dijck stamp = jiffies + 1 * HZ;
3103fd3cf5SKurt Van Dijck /* wait for card */
3203fd3cf5SKurt Van Dijck do {
3303fd3cf5SKurt Van Dijck /* DPRAM_FCT_HOST is _not_ aligned */
3403fd3cf5SKurt Van Dijck ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
3503fd3cf5SKurt Van Dijck (ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
3603fd3cf5SKurt Van Dijck /* don't have any cached variables */
3703fd3cf5SKurt Van Dijck rmb();
3803fd3cf5SKurt Van Dijck if (ret == RES_OK)
3903fd3cf5SKurt Van Dijck /* read return-value now */
4003fd3cf5SKurt Van Dijck return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
4103fd3cf5SKurt Van Dijck
4203fd3cf5SKurt Van Dijck if ((ret != vector) || time_after(jiffies, stamp))
4303fd3cf5SKurt Van Dijck break;
4403fd3cf5SKurt Van Dijck /* process context => relax */
4503fd3cf5SKurt Van Dijck usleep_range(500, 10000);
4603fd3cf5SKurt Van Dijck } while (1);
4703fd3cf5SKurt Van Dijck
4803fd3cf5SKurt Van Dijck ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
4903fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
5003fd3cf5SKurt Van Dijck return ret;
5103fd3cf5SKurt Van Dijck }
5203fd3cf5SKurt Van Dijck
softing_fct_cmd(struct softing * card,int16_t cmd,const char * msg)5303fd3cf5SKurt Van Dijck static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
5403fd3cf5SKurt Van Dijck {
5503fd3cf5SKurt Van Dijck int ret;
5603fd3cf5SKurt Van Dijck
5703fd3cf5SKurt Van Dijck ret = _softing_fct_cmd(card, cmd, 0, msg);
5803fd3cf5SKurt Van Dijck if (ret > 0) {
5903fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
6003fd3cf5SKurt Van Dijck ret = -EIO;
6103fd3cf5SKurt Van Dijck }
6203fd3cf5SKurt Van Dijck return ret;
6303fd3cf5SKurt Van Dijck }
6403fd3cf5SKurt Van Dijck
softing_bootloader_command(struct softing * card,int16_t cmd,const char * msg)6503fd3cf5SKurt Van Dijck int softing_bootloader_command(struct softing *card, int16_t cmd,
6603fd3cf5SKurt Van Dijck const char *msg)
6703fd3cf5SKurt Van Dijck {
6803fd3cf5SKurt Van Dijck int ret;
6903fd3cf5SKurt Van Dijck unsigned long stamp;
7003fd3cf5SKurt Van Dijck
7103fd3cf5SKurt Van Dijck iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
7203fd3cf5SKurt Van Dijck iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
7303fd3cf5SKurt Van Dijck /* be sure to flush this to the card */
7403fd3cf5SKurt Van Dijck wmb();
7503fd3cf5SKurt Van Dijck stamp = jiffies + 3 * HZ;
7603fd3cf5SKurt Van Dijck /* wait for card */
7703fd3cf5SKurt Van Dijck do {
7803fd3cf5SKurt Van Dijck ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
7903fd3cf5SKurt Van Dijck /* don't have any cached variables */
8003fd3cf5SKurt Van Dijck rmb();
8103fd3cf5SKurt Van Dijck if (ret == RES_OK)
8203fd3cf5SKurt Van Dijck return 0;
8303fd3cf5SKurt Van Dijck if (time_after(jiffies, stamp))
8403fd3cf5SKurt Van Dijck break;
8503fd3cf5SKurt Van Dijck /* process context => relax */
8603fd3cf5SKurt Van Dijck usleep_range(500, 10000);
8703fd3cf5SKurt Van Dijck } while (!signal_pending(current));
8803fd3cf5SKurt Van Dijck
8903fd3cf5SKurt Van Dijck ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
9003fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
9103fd3cf5SKurt Van Dijck return ret;
9203fd3cf5SKurt Van Dijck }
9303fd3cf5SKurt Van Dijck
fw_parse(const uint8_t ** pmem,uint16_t * ptype,uint32_t * paddr,uint16_t * plen,const uint8_t ** pdat)9403fd3cf5SKurt Van Dijck static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
9503fd3cf5SKurt Van Dijck uint16_t *plen, const uint8_t **pdat)
9603fd3cf5SKurt Van Dijck {
9703fd3cf5SKurt Van Dijck uint16_t checksum[2];
9803fd3cf5SKurt Van Dijck const uint8_t *mem;
9903fd3cf5SKurt Van Dijck const uint8_t *end;
10003fd3cf5SKurt Van Dijck
10103fd3cf5SKurt Van Dijck /*
10203fd3cf5SKurt Van Dijck * firmware records are a binary, unaligned stream composed of:
10303fd3cf5SKurt Van Dijck * uint16_t type;
10403fd3cf5SKurt Van Dijck * uint32_t addr;
10503fd3cf5SKurt Van Dijck * uint16_t len;
10603fd3cf5SKurt Van Dijck * uint8_t dat[len];
10703fd3cf5SKurt Van Dijck * uint16_t checksum;
10803fd3cf5SKurt Van Dijck * all values in little endian.
10903fd3cf5SKurt Van Dijck * We could define a struct for this, with __attribute__((packed)),
11003fd3cf5SKurt Van Dijck * but would that solve the alignment in _all_ cases (cfr. the
11103fd3cf5SKurt Van Dijck * struct itself may be an odd address)?
11203fd3cf5SKurt Van Dijck *
11303fd3cf5SKurt Van Dijck * I chose to use leXX_to_cpup() since this solves both
11403fd3cf5SKurt Van Dijck * endianness & alignment.
11503fd3cf5SKurt Van Dijck */
11603fd3cf5SKurt Van Dijck mem = *pmem;
11703fd3cf5SKurt Van Dijck *ptype = le16_to_cpup((void *)&mem[0]);
11803fd3cf5SKurt Van Dijck *paddr = le32_to_cpup((void *)&mem[2]);
11903fd3cf5SKurt Van Dijck *plen = le16_to_cpup((void *)&mem[6]);
12003fd3cf5SKurt Van Dijck *pdat = &mem[8];
12103fd3cf5SKurt Van Dijck /* verify checksum */
12203fd3cf5SKurt Van Dijck end = &mem[8 + *plen];
12303fd3cf5SKurt Van Dijck checksum[0] = le16_to_cpup((void *)end);
12403fd3cf5SKurt Van Dijck for (checksum[1] = 0; mem < end; ++mem)
12503fd3cf5SKurt Van Dijck checksum[1] += *mem;
12603fd3cf5SKurt Van Dijck if (checksum[0] != checksum[1])
12703fd3cf5SKurt Van Dijck return -EINVAL;
12803fd3cf5SKurt Van Dijck /* increment */
12903fd3cf5SKurt Van Dijck *pmem += 10 + *plen;
13003fd3cf5SKurt Van Dijck return 0;
13103fd3cf5SKurt Van Dijck }
13203fd3cf5SKurt Van Dijck
softing_load_fw(const char * file,struct softing * card,__iomem uint8_t * dpram,unsigned int size,int offset)13303fd3cf5SKurt Van Dijck int softing_load_fw(const char *file, struct softing *card,
13403fd3cf5SKurt Van Dijck __iomem uint8_t *dpram, unsigned int size, int offset)
13503fd3cf5SKurt Van Dijck {
13603fd3cf5SKurt Van Dijck const struct firmware *fw;
13703fd3cf5SKurt Van Dijck int ret;
13803fd3cf5SKurt Van Dijck const uint8_t *mem, *end, *dat;
13903fd3cf5SKurt Van Dijck uint16_t type, len;
14003fd3cf5SKurt Van Dijck uint32_t addr;
141ef813c41SAlexey Khoroshilov uint8_t *buf = NULL, *new_buf;
14203fd3cf5SKurt Van Dijck int buflen = 0;
14303fd3cf5SKurt Van Dijck int8_t type_end = 0;
14403fd3cf5SKurt Van Dijck
14503fd3cf5SKurt Van Dijck ret = request_firmware(&fw, file, &card->pdev->dev);
14603fd3cf5SKurt Van Dijck if (ret < 0)
14703fd3cf5SKurt Van Dijck return ret;
14803fd3cf5SKurt Van Dijck dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
14903fd3cf5SKurt Van Dijck ", offset %c0x%04x\n",
15003fd3cf5SKurt Van Dijck card->pdat->name, file, (unsigned int)fw->size,
15103fd3cf5SKurt Van Dijck (offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
15203fd3cf5SKurt Van Dijck /* parse the firmware */
15303fd3cf5SKurt Van Dijck mem = fw->data;
15403fd3cf5SKurt Van Dijck end = &mem[fw->size];
15503fd3cf5SKurt Van Dijck /* look for header record */
15603fd3cf5SKurt Van Dijck ret = fw_parse(&mem, &type, &addr, &len, &dat);
15703fd3cf5SKurt Van Dijck if (ret < 0)
15803fd3cf5SKurt Van Dijck goto failed;
15903fd3cf5SKurt Van Dijck if (type != 0xffff)
16003fd3cf5SKurt Van Dijck goto failed;
16103fd3cf5SKurt Van Dijck if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
16203fd3cf5SKurt Van Dijck ret = -EINVAL;
16303fd3cf5SKurt Van Dijck goto failed;
16403fd3cf5SKurt Van Dijck }
16503fd3cf5SKurt Van Dijck /* ok, we had a header */
16603fd3cf5SKurt Van Dijck while (mem < end) {
16703fd3cf5SKurt Van Dijck ret = fw_parse(&mem, &type, &addr, &len, &dat);
16803fd3cf5SKurt Van Dijck if (ret < 0)
16903fd3cf5SKurt Van Dijck goto failed;
17003fd3cf5SKurt Van Dijck if (type == 3) {
17103fd3cf5SKurt Van Dijck /* start address, not used here */
17203fd3cf5SKurt Van Dijck continue;
17303fd3cf5SKurt Van Dijck } else if (type == 1) {
17403fd3cf5SKurt Van Dijck /* eof */
17503fd3cf5SKurt Van Dijck type_end = 1;
17603fd3cf5SKurt Van Dijck break;
17703fd3cf5SKurt Van Dijck } else if (type != 0) {
17803fd3cf5SKurt Van Dijck ret = -EINVAL;
17903fd3cf5SKurt Van Dijck goto failed;
18003fd3cf5SKurt Van Dijck }
18103fd3cf5SKurt Van Dijck
18203fd3cf5SKurt Van Dijck if ((addr + len + offset) > size)
18303fd3cf5SKurt Van Dijck goto failed;
18403fd3cf5SKurt Van Dijck memcpy_toio(&dpram[addr + offset], dat, len);
18503fd3cf5SKurt Van Dijck /* be sure to flush caches from IO space */
18603fd3cf5SKurt Van Dijck mb();
18703fd3cf5SKurt Van Dijck if (len > buflen) {
18803fd3cf5SKurt Van Dijck /* align buflen */
18903fd3cf5SKurt Van Dijck buflen = (len + (1024-1)) & ~(1024-1);
190ef813c41SAlexey Khoroshilov new_buf = krealloc(buf, buflen, GFP_KERNEL);
191ef813c41SAlexey Khoroshilov if (!new_buf) {
19203fd3cf5SKurt Van Dijck ret = -ENOMEM;
19303fd3cf5SKurt Van Dijck goto failed;
19403fd3cf5SKurt Van Dijck }
195ef813c41SAlexey Khoroshilov buf = new_buf;
19603fd3cf5SKurt Van Dijck }
19703fd3cf5SKurt Van Dijck /* verify record data */
19803fd3cf5SKurt Van Dijck memcpy_fromio(buf, &dpram[addr + offset], len);
19903fd3cf5SKurt Van Dijck if (memcmp(buf, dat, len)) {
20003fd3cf5SKurt Van Dijck /* is not ok */
20103fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
20203fd3cf5SKurt Van Dijck ret = -EIO;
20303fd3cf5SKurt Van Dijck goto failed;
20403fd3cf5SKurt Van Dijck }
20503fd3cf5SKurt Van Dijck }
20603fd3cf5SKurt Van Dijck if (!type_end)
20703fd3cf5SKurt Van Dijck /* no end record seen */
20803fd3cf5SKurt Van Dijck goto failed;
20903fd3cf5SKurt Van Dijck ret = 0;
21003fd3cf5SKurt Van Dijck failed:
21103fd3cf5SKurt Van Dijck kfree(buf);
21203fd3cf5SKurt Van Dijck release_firmware(fw);
21303fd3cf5SKurt Van Dijck if (ret < 0)
21403fd3cf5SKurt Van Dijck dev_info(&card->pdev->dev, "firmware %s failed\n", file);
21503fd3cf5SKurt Van Dijck return ret;
21603fd3cf5SKurt Van Dijck }
21703fd3cf5SKurt Van Dijck
softing_load_app_fw(const char * file,struct softing * card)21803fd3cf5SKurt Van Dijck int softing_load_app_fw(const char *file, struct softing *card)
21903fd3cf5SKurt Van Dijck {
22003fd3cf5SKurt Van Dijck const struct firmware *fw;
22103fd3cf5SKurt Van Dijck const uint8_t *mem, *end, *dat;
22203fd3cf5SKurt Van Dijck int ret, j;
22303fd3cf5SKurt Van Dijck uint16_t type, len;
22403fd3cf5SKurt Van Dijck uint32_t addr, start_addr = 0;
22503fd3cf5SKurt Van Dijck unsigned int sum, rx_sum;
22603fd3cf5SKurt Van Dijck int8_t type_end = 0, type_entrypoint = 0;
22703fd3cf5SKurt Van Dijck
22803fd3cf5SKurt Van Dijck ret = request_firmware(&fw, file, &card->pdev->dev);
22903fd3cf5SKurt Van Dijck if (ret) {
23003fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
23103fd3cf5SKurt Van Dijck file, ret);
23203fd3cf5SKurt Van Dijck return ret;
23303fd3cf5SKurt Van Dijck }
23403fd3cf5SKurt Van Dijck dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
23503fd3cf5SKurt Van Dijck file, (unsigned long)fw->size);
23603fd3cf5SKurt Van Dijck /* parse the firmware */
23703fd3cf5SKurt Van Dijck mem = fw->data;
23803fd3cf5SKurt Van Dijck end = &mem[fw->size];
23903fd3cf5SKurt Van Dijck /* look for header record */
24003fd3cf5SKurt Van Dijck ret = fw_parse(&mem, &type, &addr, &len, &dat);
24103fd3cf5SKurt Van Dijck if (ret)
24203fd3cf5SKurt Van Dijck goto failed;
24303fd3cf5SKurt Van Dijck ret = -EINVAL;
24403fd3cf5SKurt Van Dijck if (type != 0xffff) {
24503fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
24603fd3cf5SKurt Van Dijck type);
24703fd3cf5SKurt Van Dijck goto failed;
24803fd3cf5SKurt Van Dijck }
24903fd3cf5SKurt Van Dijck if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
25003fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
25103fd3cf5SKurt Van Dijck len, dat);
25203fd3cf5SKurt Van Dijck goto failed;
25303fd3cf5SKurt Van Dijck }
25403fd3cf5SKurt Van Dijck /* ok, we had a header */
25503fd3cf5SKurt Van Dijck while (mem < end) {
25603fd3cf5SKurt Van Dijck ret = fw_parse(&mem, &type, &addr, &len, &dat);
25703fd3cf5SKurt Van Dijck if (ret)
25803fd3cf5SKurt Van Dijck goto failed;
25903fd3cf5SKurt Van Dijck
26003fd3cf5SKurt Van Dijck if (type == 3) {
26103fd3cf5SKurt Van Dijck /* start address */
26203fd3cf5SKurt Van Dijck start_addr = addr;
26303fd3cf5SKurt Van Dijck type_entrypoint = 1;
26403fd3cf5SKurt Van Dijck continue;
26503fd3cf5SKurt Van Dijck } else if (type == 1) {
26603fd3cf5SKurt Van Dijck /* eof */
26703fd3cf5SKurt Van Dijck type_end = 1;
26803fd3cf5SKurt Van Dijck break;
26903fd3cf5SKurt Van Dijck } else if (type != 0) {
27003fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev,
27103fd3cf5SKurt Van Dijck "unknown record type 0x%04x\n", type);
27203fd3cf5SKurt Van Dijck ret = -EINVAL;
27303fd3cf5SKurt Van Dijck goto failed;
27403fd3cf5SKurt Van Dijck }
27503fd3cf5SKurt Van Dijck
27688bfb9a7SMarc Kleine-Budde /* regular data */
27703fd3cf5SKurt Van Dijck for (sum = 0, j = 0; j < len; ++j)
27803fd3cf5SKurt Van Dijck sum += dat[j];
27903fd3cf5SKurt Van Dijck /* work in 16bit (target) */
28003fd3cf5SKurt Van Dijck sum &= 0xffff;
28103fd3cf5SKurt Van Dijck
28203fd3cf5SKurt Van Dijck memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
28303fd3cf5SKurt Van Dijck iowrite32(card->pdat->app.offs + card->pdat->app.addr,
28403fd3cf5SKurt Van Dijck &card->dpram[DPRAM_COMMAND + 2]);
28503fd3cf5SKurt Van Dijck iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
28603fd3cf5SKurt Van Dijck iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
28703fd3cf5SKurt Van Dijck iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
28803fd3cf5SKurt Van Dijck ret = softing_bootloader_command(card, 1, "loading app.");
28903fd3cf5SKurt Van Dijck if (ret < 0)
29003fd3cf5SKurt Van Dijck goto failed;
29103fd3cf5SKurt Van Dijck /* verify checksum */
29203fd3cf5SKurt Van Dijck rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
29303fd3cf5SKurt Van Dijck if (rx_sum != sum) {
29403fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
29503fd3cf5SKurt Van Dijck ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
29603fd3cf5SKurt Van Dijck ret = -EIO;
29703fd3cf5SKurt Van Dijck goto failed;
29803fd3cf5SKurt Van Dijck }
29903fd3cf5SKurt Van Dijck }
30003fd3cf5SKurt Van Dijck if (!type_end || !type_entrypoint)
30103fd3cf5SKurt Van Dijck goto failed;
30203fd3cf5SKurt Van Dijck /* start application in card */
30303fd3cf5SKurt Van Dijck iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
30403fd3cf5SKurt Van Dijck iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
30503fd3cf5SKurt Van Dijck ret = softing_bootloader_command(card, 3, "start app.");
30603fd3cf5SKurt Van Dijck if (ret < 0)
30703fd3cf5SKurt Van Dijck goto failed;
30803fd3cf5SKurt Van Dijck ret = 0;
30903fd3cf5SKurt Van Dijck failed:
31003fd3cf5SKurt Van Dijck release_firmware(fw);
31103fd3cf5SKurt Van Dijck if (ret < 0)
31203fd3cf5SKurt Van Dijck dev_info(&card->pdev->dev, "firmware %s failed\n", file);
31303fd3cf5SKurt Van Dijck return ret;
31403fd3cf5SKurt Van Dijck }
31503fd3cf5SKurt Van Dijck
softing_reset_chip(struct softing * card)31603fd3cf5SKurt Van Dijck static int softing_reset_chip(struct softing *card)
31703fd3cf5SKurt Van Dijck {
31803fd3cf5SKurt Van Dijck int ret;
31903fd3cf5SKurt Van Dijck
32003fd3cf5SKurt Van Dijck do {
32103fd3cf5SKurt Van Dijck /* reset chip */
32203fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
32303fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
32403fd3cf5SKurt Van Dijck iowrite8(1, &card->dpram[DPRAM_RESET]);
32503fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_RESET+1]);
32603fd3cf5SKurt Van Dijck
32703fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 0, "reset_can");
32803fd3cf5SKurt Van Dijck if (!ret)
32903fd3cf5SKurt Van Dijck break;
33003fd3cf5SKurt Van Dijck if (signal_pending(current))
33103fd3cf5SKurt Van Dijck /* don't wait any longer */
33203fd3cf5SKurt Van Dijck break;
33303fd3cf5SKurt Van Dijck } while (1);
33403fd3cf5SKurt Van Dijck card->tx.pending = 0;
33503fd3cf5SKurt Van Dijck return ret;
33603fd3cf5SKurt Van Dijck }
33703fd3cf5SKurt Van Dijck
softing_chip_poweron(struct softing * card)33803fd3cf5SKurt Van Dijck int softing_chip_poweron(struct softing *card)
33903fd3cf5SKurt Van Dijck {
34003fd3cf5SKurt Van Dijck int ret;
34103fd3cf5SKurt Van Dijck /* sync */
34203fd3cf5SKurt Van Dijck ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
34303fd3cf5SKurt Van Dijck if (ret < 0)
34403fd3cf5SKurt Van Dijck goto failed;
34503fd3cf5SKurt Van Dijck
34603fd3cf5SKurt Van Dijck ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
34703fd3cf5SKurt Van Dijck if (ret < 0)
34803fd3cf5SKurt Van Dijck goto failed;
34903fd3cf5SKurt Van Dijck
35003fd3cf5SKurt Van Dijck ret = softing_reset_chip(card);
35103fd3cf5SKurt Van Dijck if (ret < 0)
35203fd3cf5SKurt Van Dijck goto failed;
35303fd3cf5SKurt Van Dijck /* get_serial */
35403fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 43, "get_serial_number");
35503fd3cf5SKurt Van Dijck if (ret < 0)
35603fd3cf5SKurt Van Dijck goto failed;
35703fd3cf5SKurt Van Dijck card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
35803fd3cf5SKurt Van Dijck /* get_version */
35903fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 12, "get_version");
36003fd3cf5SKurt Van Dijck if (ret < 0)
36103fd3cf5SKurt Van Dijck goto failed;
36203fd3cf5SKurt Van Dijck card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
36303fd3cf5SKurt Van Dijck card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
36403fd3cf5SKurt Van Dijck card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
36503fd3cf5SKurt Van Dijck card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
36603fd3cf5SKurt Van Dijck card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
36703fd3cf5SKurt Van Dijck return 0;
36803fd3cf5SKurt Van Dijck failed:
36903fd3cf5SKurt Van Dijck return ret;
37003fd3cf5SKurt Van Dijck }
37103fd3cf5SKurt Van Dijck
softing_initialize_timestamp(struct softing * card)37203fd3cf5SKurt Van Dijck static void softing_initialize_timestamp(struct softing *card)
37303fd3cf5SKurt Van Dijck {
37403fd3cf5SKurt Van Dijck uint64_t ovf;
37503fd3cf5SKurt Van Dijck
37603fd3cf5SKurt Van Dijck card->ts_ref = ktime_get();
37703fd3cf5SKurt Van Dijck
37803fd3cf5SKurt Van Dijck /* 16MHz is the reference */
37903fd3cf5SKurt Van Dijck ovf = 0x100000000ULL * 16;
38003fd3cf5SKurt Van Dijck do_div(ovf, card->pdat->freq ?: 16);
38103fd3cf5SKurt Van Dijck
3828b0e1953SThomas Gleixner card->ts_overflow = ktime_add_us(0, ovf);
38303fd3cf5SKurt Van Dijck }
38403fd3cf5SKurt Van Dijck
softing_raw2ktime(struct softing * card,u32 raw)38503fd3cf5SKurt Van Dijck ktime_t softing_raw2ktime(struct softing *card, u32 raw)
38603fd3cf5SKurt Van Dijck {
38703fd3cf5SKurt Van Dijck uint64_t rawl;
38803fd3cf5SKurt Van Dijck ktime_t now, real_offset;
38903fd3cf5SKurt Van Dijck ktime_t target;
39003fd3cf5SKurt Van Dijck ktime_t tmp;
39103fd3cf5SKurt Van Dijck
39203fd3cf5SKurt Van Dijck now = ktime_get();
39303fd3cf5SKurt Van Dijck real_offset = ktime_sub(ktime_get_real(), now);
39403fd3cf5SKurt Van Dijck
39503fd3cf5SKurt Van Dijck /* find nsec from card */
39603fd3cf5SKurt Van Dijck rawl = raw * 16;
39703fd3cf5SKurt Van Dijck do_div(rawl, card->pdat->freq ?: 16);
39803fd3cf5SKurt Van Dijck target = ktime_add_us(card->ts_ref, rawl);
39903fd3cf5SKurt Van Dijck /* test for overflows */
40003fd3cf5SKurt Van Dijck tmp = ktime_add(target, card->ts_overflow);
40103fd3cf5SKurt Van Dijck while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
40203fd3cf5SKurt Van Dijck card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
40303fd3cf5SKurt Van Dijck target = tmp;
40403fd3cf5SKurt Van Dijck tmp = ktime_add(target, card->ts_overflow);
40503fd3cf5SKurt Van Dijck }
40603fd3cf5SKurt Van Dijck return ktime_add(target, real_offset);
40703fd3cf5SKurt Van Dijck }
40803fd3cf5SKurt Van Dijck
softing_error_reporting(struct net_device * netdev)40903fd3cf5SKurt Van Dijck static inline int softing_error_reporting(struct net_device *netdev)
41003fd3cf5SKurt Van Dijck {
41103fd3cf5SKurt Van Dijck struct softing_priv *priv = netdev_priv(netdev);
41203fd3cf5SKurt Van Dijck
41303fd3cf5SKurt Van Dijck return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
41403fd3cf5SKurt Van Dijck ? 1 : 0;
41503fd3cf5SKurt Van Dijck }
41603fd3cf5SKurt Van Dijck
softing_startstop(struct net_device * dev,int up)41703fd3cf5SKurt Van Dijck int softing_startstop(struct net_device *dev, int up)
41803fd3cf5SKurt Van Dijck {
41903fd3cf5SKurt Van Dijck int ret;
42003fd3cf5SKurt Van Dijck struct softing *card;
42103fd3cf5SKurt Van Dijck struct softing_priv *priv;
42203fd3cf5SKurt Van Dijck struct net_device *netdev;
42303fd3cf5SKurt Van Dijck int bus_bitmask_start;
42403fd3cf5SKurt Van Dijck int j, error_reporting;
42503fd3cf5SKurt Van Dijck struct can_frame msg;
42603fd3cf5SKurt Van Dijck const struct can_bittiming *bt;
42703fd3cf5SKurt Van Dijck
42803fd3cf5SKurt Van Dijck priv = netdev_priv(dev);
42903fd3cf5SKurt Van Dijck card = priv->card;
43003fd3cf5SKurt Van Dijck
43103fd3cf5SKurt Van Dijck if (!card->fw.up)
43203fd3cf5SKurt Van Dijck return -EIO;
43303fd3cf5SKurt Van Dijck
43403fd3cf5SKurt Van Dijck ret = mutex_lock_interruptible(&card->fw.lock);
43503fd3cf5SKurt Van Dijck if (ret)
43603fd3cf5SKurt Van Dijck return ret;
43703fd3cf5SKurt Van Dijck
43803fd3cf5SKurt Van Dijck bus_bitmask_start = 0;
43903fd3cf5SKurt Van Dijck if (dev && up)
44003fd3cf5SKurt Van Dijck /* prepare to start this bus as well */
44103fd3cf5SKurt Van Dijck bus_bitmask_start |= (1 << priv->index);
44203fd3cf5SKurt Van Dijck /* bring netdevs down */
44303fd3cf5SKurt Van Dijck for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
44403fd3cf5SKurt Van Dijck netdev = card->net[j];
44503fd3cf5SKurt Van Dijck if (!netdev)
44603fd3cf5SKurt Van Dijck continue;
44703fd3cf5SKurt Van Dijck priv = netdev_priv(netdev);
44803fd3cf5SKurt Van Dijck
44903fd3cf5SKurt Van Dijck if (dev != netdev)
45003fd3cf5SKurt Van Dijck netif_stop_queue(netdev);
45103fd3cf5SKurt Van Dijck
45203fd3cf5SKurt Van Dijck if (netif_running(netdev)) {
45303fd3cf5SKurt Van Dijck if (dev != netdev)
45403fd3cf5SKurt Van Dijck bus_bitmask_start |= (1 << j);
45503fd3cf5SKurt Van Dijck priv->tx.pending = 0;
45603fd3cf5SKurt Van Dijck priv->tx.echo_put = 0;
45703fd3cf5SKurt Van Dijck priv->tx.echo_get = 0;
45803fd3cf5SKurt Van Dijck /*
45903fd3cf5SKurt Van Dijck * this bus' may just have called open_candev()
46003fd3cf5SKurt Van Dijck * which is rather stupid to call close_candev()
46103fd3cf5SKurt Van Dijck * already
46203fd3cf5SKurt Van Dijck * but we may come here from busoff recovery too
46303fd3cf5SKurt Van Dijck * in which case the echo_skb _needs_ flushing too.
46403fd3cf5SKurt Van Dijck * just be sure to call open_candev() again
46503fd3cf5SKurt Van Dijck */
46603fd3cf5SKurt Van Dijck close_candev(netdev);
46703fd3cf5SKurt Van Dijck }
46803fd3cf5SKurt Van Dijck priv->can.state = CAN_STATE_STOPPED;
46903fd3cf5SKurt Van Dijck }
47003fd3cf5SKurt Van Dijck card->tx.pending = 0;
47103fd3cf5SKurt Van Dijck
47203fd3cf5SKurt Van Dijck softing_enable_irq(card, 0);
47303fd3cf5SKurt Van Dijck ret = softing_reset_chip(card);
47403fd3cf5SKurt Van Dijck if (ret)
47503fd3cf5SKurt Van Dijck goto failed;
47603fd3cf5SKurt Van Dijck if (!bus_bitmask_start)
47788bfb9a7SMarc Kleine-Budde /* no buses to be brought up */
47803fd3cf5SKurt Van Dijck goto card_done;
47903fd3cf5SKurt Van Dijck
48003fd3cf5SKurt Van Dijck if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
48103fd3cf5SKurt Van Dijck && (softing_error_reporting(card->net[0])
48203fd3cf5SKurt Van Dijck != softing_error_reporting(card->net[1]))) {
48303fd3cf5SKurt Van Dijck dev_alert(&card->pdev->dev,
48488bfb9a7SMarc Kleine-Budde "err_reporting flag differs for buses\n");
48503fd3cf5SKurt Van Dijck goto invalid;
48603fd3cf5SKurt Van Dijck }
48703fd3cf5SKurt Van Dijck error_reporting = 0;
48803fd3cf5SKurt Van Dijck if (bus_bitmask_start & 1) {
48903fd3cf5SKurt Van Dijck netdev = card->net[0];
49003fd3cf5SKurt Van Dijck priv = netdev_priv(netdev);
49103fd3cf5SKurt Van Dijck error_reporting += softing_error_reporting(netdev);
49203fd3cf5SKurt Van Dijck /* init chip 1 */
49303fd3cf5SKurt Van Dijck bt = &priv->can.bittiming;
49403fd3cf5SKurt Van Dijck iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
49503fd3cf5SKurt Van Dijck iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
49603fd3cf5SKurt Van Dijck iowrite16(bt->phase_seg1 + bt->prop_seg,
49703fd3cf5SKurt Van Dijck &card->dpram[DPRAM_FCT_PARAM + 6]);
49803fd3cf5SKurt Van Dijck iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
49903fd3cf5SKurt Van Dijck iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
50003fd3cf5SKurt Van Dijck &card->dpram[DPRAM_FCT_PARAM + 10]);
50103fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
50203fd3cf5SKurt Van Dijck if (ret < 0)
50303fd3cf5SKurt Van Dijck goto failed;
50403fd3cf5SKurt Van Dijck /* set mode */
50503fd3cf5SKurt Van Dijck iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
50603fd3cf5SKurt Van Dijck iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
50703fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 3, "set_mode[0]");
50803fd3cf5SKurt Van Dijck if (ret < 0)
50903fd3cf5SKurt Van Dijck goto failed;
51003fd3cf5SKurt Van Dijck /* set filter */
51103fd3cf5SKurt Van Dijck /* 11bit id & mask */
51203fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
51303fd3cf5SKurt Van Dijck iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
51403fd3cf5SKurt Van Dijck /* 29bit id.lo & mask.lo & id.hi & mask.hi */
51503fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
51603fd3cf5SKurt Van Dijck iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
51703fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
51803fd3cf5SKurt Van Dijck iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
51903fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 7, "set_filter[0]");
52003fd3cf5SKurt Van Dijck if (ret < 0)
52103fd3cf5SKurt Van Dijck goto failed;
52203fd3cf5SKurt Van Dijck /* set output control */
52303fd3cf5SKurt Van Dijck iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
52403fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 5, "set_output[0]");
52503fd3cf5SKurt Van Dijck if (ret < 0)
52603fd3cf5SKurt Van Dijck goto failed;
52703fd3cf5SKurt Van Dijck }
52803fd3cf5SKurt Van Dijck if (bus_bitmask_start & 2) {
52903fd3cf5SKurt Van Dijck netdev = card->net[1];
53003fd3cf5SKurt Van Dijck priv = netdev_priv(netdev);
53103fd3cf5SKurt Van Dijck error_reporting += softing_error_reporting(netdev);
53203fd3cf5SKurt Van Dijck /* init chip2 */
53303fd3cf5SKurt Van Dijck bt = &priv->can.bittiming;
53403fd3cf5SKurt Van Dijck iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
53503fd3cf5SKurt Van Dijck iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
53603fd3cf5SKurt Van Dijck iowrite16(bt->phase_seg1 + bt->prop_seg,
53703fd3cf5SKurt Van Dijck &card->dpram[DPRAM_FCT_PARAM + 6]);
53803fd3cf5SKurt Van Dijck iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
53903fd3cf5SKurt Van Dijck iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
54003fd3cf5SKurt Van Dijck &card->dpram[DPRAM_FCT_PARAM + 10]);
54103fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
54203fd3cf5SKurt Van Dijck if (ret < 0)
54303fd3cf5SKurt Van Dijck goto failed;
54403fd3cf5SKurt Van Dijck /* set mode2 */
54503fd3cf5SKurt Van Dijck iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
54603fd3cf5SKurt Van Dijck iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
54703fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 4, "set_mode[1]");
54803fd3cf5SKurt Van Dijck if (ret < 0)
54903fd3cf5SKurt Van Dijck goto failed;
55003fd3cf5SKurt Van Dijck /* set filter2 */
55103fd3cf5SKurt Van Dijck /* 11bit id & mask */
55203fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
55303fd3cf5SKurt Van Dijck iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
55403fd3cf5SKurt Van Dijck /* 29bit id.lo & mask.lo & id.hi & mask.hi */
55503fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
55603fd3cf5SKurt Van Dijck iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
55703fd3cf5SKurt Van Dijck iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
55803fd3cf5SKurt Van Dijck iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
55903fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 8, "set_filter[1]");
56003fd3cf5SKurt Van Dijck if (ret < 0)
56103fd3cf5SKurt Van Dijck goto failed;
56203fd3cf5SKurt Van Dijck /* set output control2 */
56303fd3cf5SKurt Van Dijck iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
56403fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 6, "set_output[1]");
56503fd3cf5SKurt Van Dijck if (ret < 0)
56603fd3cf5SKurt Van Dijck goto failed;
56703fd3cf5SKurt Van Dijck }
568*370d988cSMarc Kleine-Budde
569*370d988cSMarc Kleine-Budde /* enable_error_frame
570*370d988cSMarc Kleine-Budde *
57103fd3cf5SKurt Van Dijck * Error reporting is switched off at the moment since
57203fd3cf5SKurt Van Dijck * the receiving of them is not yet 100% verified
57303fd3cf5SKurt Van Dijck * This should be enabled sooner or later
574*370d988cSMarc Kleine-Budde */
575*370d988cSMarc Kleine-Budde if (0 && error_reporting) {
57603fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 51, "enable_error_frame");
57703fd3cf5SKurt Van Dijck if (ret < 0)
57803fd3cf5SKurt Van Dijck goto failed;
57903fd3cf5SKurt Van Dijck }
580*370d988cSMarc Kleine-Budde
58103fd3cf5SKurt Van Dijck /* initialize interface */
58203fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
58303fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
58403fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
58503fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
58603fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
58703fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
58803fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
58903fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
59003fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
59103fd3cf5SKurt Van Dijck iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
59203fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 17, "initialize_interface");
59303fd3cf5SKurt Van Dijck if (ret < 0)
59403fd3cf5SKurt Van Dijck goto failed;
59503fd3cf5SKurt Van Dijck /* enable_fifo */
59603fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 36, "enable_fifo");
59703fd3cf5SKurt Van Dijck if (ret < 0)
59803fd3cf5SKurt Van Dijck goto failed;
59903fd3cf5SKurt Van Dijck /* enable fifo tx ack */
60003fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
60103fd3cf5SKurt Van Dijck if (ret < 0)
60203fd3cf5SKurt Van Dijck goto failed;
60303fd3cf5SKurt Van Dijck /* enable fifo tx ack2 */
60403fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
60503fd3cf5SKurt Van Dijck if (ret < 0)
60603fd3cf5SKurt Van Dijck goto failed;
60703fd3cf5SKurt Van Dijck /* start_chip */
60803fd3cf5SKurt Van Dijck ret = softing_fct_cmd(card, 11, "start_chip");
60903fd3cf5SKurt Van Dijck if (ret < 0)
61003fd3cf5SKurt Van Dijck goto failed;
61103fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
61203fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
61303fd3cf5SKurt Van Dijck if (card->pdat->generation < 2) {
61403fd3cf5SKurt Van Dijck iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
61503fd3cf5SKurt Van Dijck /* flush the DPRAM caches */
61603fd3cf5SKurt Van Dijck wmb();
61703fd3cf5SKurt Van Dijck }
61803fd3cf5SKurt Van Dijck
61903fd3cf5SKurt Van Dijck softing_initialize_timestamp(card);
62003fd3cf5SKurt Van Dijck
62103fd3cf5SKurt Van Dijck /*
62203fd3cf5SKurt Van Dijck * do socketcan notifications/status changes
62303fd3cf5SKurt Van Dijck * from here, no errors should occur, or the failed: part
62403fd3cf5SKurt Van Dijck * must be reviewed
62503fd3cf5SKurt Van Dijck */
62603fd3cf5SKurt Van Dijck memset(&msg, 0, sizeof(msg));
62703fd3cf5SKurt Van Dijck msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
628c7b74967SOliver Hartkopp msg.len = CAN_ERR_DLC;
62903fd3cf5SKurt Van Dijck for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
63003fd3cf5SKurt Van Dijck if (!(bus_bitmask_start & (1 << j)))
63103fd3cf5SKurt Van Dijck continue;
63203fd3cf5SKurt Van Dijck netdev = card->net[j];
63303fd3cf5SKurt Van Dijck if (!netdev)
63403fd3cf5SKurt Van Dijck continue;
63503fd3cf5SKurt Van Dijck priv = netdev_priv(netdev);
63603fd3cf5SKurt Van Dijck priv->can.state = CAN_STATE_ERROR_ACTIVE;
63703fd3cf5SKurt Van Dijck open_candev(netdev);
63803fd3cf5SKurt Van Dijck if (dev != netdev) {
63988bfb9a7SMarc Kleine-Budde /* notify other buses on the restart */
6408b0e1953SThomas Gleixner softing_netdev_rx(netdev, &msg, 0);
64103fd3cf5SKurt Van Dijck ++priv->can.can_stats.restarts;
64203fd3cf5SKurt Van Dijck }
64303fd3cf5SKurt Van Dijck netif_wake_queue(netdev);
64403fd3cf5SKurt Van Dijck }
64503fd3cf5SKurt Van Dijck
64603fd3cf5SKurt Van Dijck /* enable interrupts */
64703fd3cf5SKurt Van Dijck ret = softing_enable_irq(card, 1);
64803fd3cf5SKurt Van Dijck if (ret)
64903fd3cf5SKurt Van Dijck goto failed;
65003fd3cf5SKurt Van Dijck card_done:
65103fd3cf5SKurt Van Dijck mutex_unlock(&card->fw.lock);
65203fd3cf5SKurt Van Dijck return 0;
65303fd3cf5SKurt Van Dijck invalid:
65403fd3cf5SKurt Van Dijck ret = -EINVAL;
65503fd3cf5SKurt Van Dijck failed:
65603fd3cf5SKurt Van Dijck softing_enable_irq(card, 0);
65703fd3cf5SKurt Van Dijck softing_reset_chip(card);
65803fd3cf5SKurt Van Dijck mutex_unlock(&card->fw.lock);
65903fd3cf5SKurt Van Dijck /* bring all other interfaces down */
66003fd3cf5SKurt Van Dijck for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
66103fd3cf5SKurt Van Dijck netdev = card->net[j];
66203fd3cf5SKurt Van Dijck if (!netdev)
66303fd3cf5SKurt Van Dijck continue;
66403fd3cf5SKurt Van Dijck dev_close(netdev);
66503fd3cf5SKurt Van Dijck }
66603fd3cf5SKurt Van Dijck return ret;
66703fd3cf5SKurt Van Dijck }
66803fd3cf5SKurt Van Dijck
softing_default_output(struct net_device * netdev)66903fd3cf5SKurt Van Dijck int softing_default_output(struct net_device *netdev)
67003fd3cf5SKurt Van Dijck {
67103fd3cf5SKurt Van Dijck struct softing_priv *priv = netdev_priv(netdev);
67203fd3cf5SKurt Van Dijck struct softing *card = priv->card;
67303fd3cf5SKurt Van Dijck
67403fd3cf5SKurt Van Dijck switch (priv->chip) {
67503fd3cf5SKurt Van Dijck case 1000:
67603fd3cf5SKurt Van Dijck return (card->pdat->generation < 2) ? 0xfb : 0xfa;
67703fd3cf5SKurt Van Dijck case 5:
67803fd3cf5SKurt Van Dijck return 0x60;
67903fd3cf5SKurt Van Dijck default:
68003fd3cf5SKurt Van Dijck return 0x40;
68103fd3cf5SKurt Van Dijck }
68203fd3cf5SKurt Van Dijck }
683