|  | /* | 
|  | * 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, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  | #include <linux/firmware.h> | 
|  | #include <linux/sched.h> | 
|  | #include <asm/div64.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; | 
|  | int buflen = 0; | 
|  | int8_t type_end = 0; | 
|  |  | 
|  | ret = request_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); | 
|  | buf = krealloc(buf, buflen, GFP_KERNEL); | 
|  | if (!buf) { | 
|  | ret = -ENOMEM; | 
|  | goto failed; | 
|  | } | 
|  | } | 
|  | /* 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 = request_firmware(&fw, file, &card->pdev->dev); | 
|  | if (ret) { | 
|  | dev_alert(&card->pdev->dev, "request_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; | 
|  | } | 
|  | } |