// SPDX-License-Identifier: GPL-2.0-only 
 | 
/* 
 | 
 * Copyright (C) 2008-2010 
 | 
 * 
 | 
 * - Kurt Van Dijck, EIA Electronics 
 | 
 */ 
 | 
  
 | 
#include <linux/firmware.h> 
 | 
#include <linux/sched/signal.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 = 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); 
 | 
            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 = 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; 
 | 
        } 
 | 
  
 | 
        /* regular 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(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 buses 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 buses\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 (0 && 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 buses on the restart */ 
 | 
            softing_netdev_rx(netdev, &msg, 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; 
 | 
    } 
 | 
} 
 |