/* * Initialize the signed boot process * * @i2400m: device descriptor * * @bcf_hdr: pointer to the firmware header; assumes it is fully in * memory (it has gone through basic validation). * * Returns: 0 if ok, < 0 errno code on error, -ERESTARTSYS if the hw * rebooted. * * This writes the firmware BCF header to the device using the * HASH_PAYLOAD_ONLY command. */ static int i2400m_dnload_init_signed(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf_hdr) { int ret; struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; struct i2400m_bcf_hdr cmd_pl; } __packed *cmd_buf; struct i2400m_bootrom_header ack; d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr); cmd_buf = i2400m->bm_cmd_buf; cmd_buf->cmd.command = i2400m_brh_command(I2400M_BRH_HASH_PAYLOAD_ONLY, 0, 0); cmd_buf->cmd.target_addr = 0; cmd_buf->cmd.data_size = cpu_to_le32(sizeof(cmd_buf->cmd_pl)); memcpy(&cmd_buf->cmd_pl, bcf_hdr, sizeof(*bcf_hdr)); ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(*cmd_buf), &ack, sizeof(ack), 0); if (ret >= 0) ret = 0; d_fnend(5, dev, "(i2400m %p bcf_hdr %p) = %d\n", i2400m, bcf_hdr, ret); return ret; }
/** * i2400m_download_chunk - write a single chunk of data to the device's memory * * @i2400m: device descriptor * @buf: the buffer to write * @buf_len: length of the buffer to write * @addr: address in the device memory space * @direct: bootrom write mode * @do_csum: should a checksum validation be performed */ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk, size_t __chunk_len, unsigned long addr, unsigned int direct, unsigned int do_csum) { int ret; size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN); struct device *dev = i2400m_dev(i2400m); struct { struct i2400m_bootrom_header cmd; u8 cmd_payload[chunk_len]; } __packed *buf; struct i2400m_bootrom_header ack; d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx " "direct %u do_csum %u)\n", i2400m, chunk, __chunk_len, addr, direct, do_csum); buf = i2400m->bm_cmd_buf; memcpy(buf->cmd_payload, chunk, __chunk_len); memset(buf->cmd_payload + __chunk_len, 0xad, chunk_len - __chunk_len); buf->cmd.command = i2400m_brh_command(I2400M_BRH_WRITE, __chunk_len & 0x3 ? 0 : do_csum, __chunk_len & 0xf ? 0 : direct); buf->cmd.target_addr = cpu_to_le32(addr); buf->cmd.data_size = cpu_to_le32(__chunk_len); ret = i2400m_bm_cmd(i2400m, &buf->cmd, sizeof(buf->cmd) + chunk_len, &ack, sizeof(ack), 0); if (ret >= 0) ret = 0; d_fnend(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx " "direct %u do_csum %u) = %d\n", i2400m, chunk, __chunk_len, addr, direct, do_csum, ret); return ret; }
/* * Read the MAC addr * * The position this function reads is fixed in device memory and * always available, even without firmware. * * Note we specify we want to read only six bytes, but provide space * for 16, as we always get it rounded up. */ int i2400m_read_mac_addr(struct i2400m *i2400m) { int result; struct device *dev = i2400m_dev(i2400m); struct net_device *net_dev = i2400m->wimax_dev.net_dev; struct i2400m_bootrom_header *cmd; struct { struct i2400m_bootrom_header ack; u8 ack_pl[16]; } __packed ack_buf; d_fnstart(5, dev, "(i2400m %p)\n", i2400m); cmd = i2400m->bm_cmd_buf; cmd->command = i2400m_brh_command(I2400M_BRH_READ, 0, 1); cmd->target_addr = cpu_to_le32(0x00203fe8); cmd->data_size = cpu_to_le32(6); result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd), &ack_buf.ack, sizeof(ack_buf), 0); if (result < 0) { dev_err(dev, "BM: read mac addr failed: %d\n", result); goto error_read_mac; } d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl); if (i2400m->bus_bm_mac_addr_impaired == 1) { ack_buf.ack_pl[0] = 0x00; ack_buf.ack_pl[1] = 0x16; ack_buf.ack_pl[2] = 0xd3; get_random_bytes(&ack_buf.ack_pl[3], 3); dev_err(dev, "BM is MAC addr impaired, faking MAC addr to " "mac addr is %pM\n", ack_buf.ack_pl); result = 0; } net_dev->addr_len = ETH_ALEN; memcpy(net_dev->perm_addr, ack_buf.ack_pl, ETH_ALEN); memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN); error_read_mac: d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result); return result; }