* [PATCH net-next v4 0/2] Add support for the ethernet switch on the ESPRESSObin
From: Romain Perier @ 2016-12-21 12:57 UTC (permalink / raw)
To: linux-arm-kernel
This set of patches adds support for the Marvell ethernet switch 88E6341.
It also add the devicetree definition of this switch to the DT board.
Romain Perier (2):
net: dsa: mv88e6xxx: Don't forbid MDIO I/Os for PHY addr >=
num_of_ports
net: dsa: mv88e6xxx: Add support for ethernet switch 88E6341/88E6141
drivers/net/dsa/mv88e6xxx/chip.c | 48 ++++++++++++++++++++++++++++++-----
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 4 ++-
2 files changed, 45 insertions(+), 7 deletions(-)
--
Note: As requested by Gregory, I have removed the patch for the DT (already merged).
2.9.3
^ permalink raw reply
* [RFC PATCH 5/7] Multiple VF's grouped together under single physical port called PF group PF Group maintainance API's
From: Sunil Kovvuri @ 2016-12-21 12:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482310011-1862-6-git-send-email-satha.rao@caviumnetworks.com>
On Wed, Dec 21, 2016 at 2:16 PM, Satha Koteswara Rao
<satha.rao@caviumnetworks.com> wrote:
> +struct tns_global_st {
> + u64 magic;
> + char version[16];
> + u64 reg_cnt;
> + struct table_static_s tbl_info[TNS_MAX_TABLE];
> +};
> +
> +#define PF_COUNT 3
> +#define PF_1 0
> +#define PF_2 64
> +#define PF_3 96
> +#define PF_END 128
Some comments please ... what is 0, 64, 96 ??
You can read PCI_SRIOV_TOTAL_VF from PCI config space instead of
defining PF_END with 128.
^ permalink raw reply
* [RFC PATCH 4/7] HW Filter Initialization code and register access APIs
From: Sunil Kovvuri @ 2016-12-21 12:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482310011-1862-5-git-send-email-satha.rao@caviumnetworks.com>
On Wed, Dec 21, 2016 at 2:16 PM, Satha Koteswara Rao
<satha.rao@caviumnetworks.com> wrote:
> ---
> drivers/net/ethernet/cavium/thunder/pf_reg.c | 660 +++++++++++++++++++++++++++
> 1 file changed, 660 insertions(+)
> create mode 100644 drivers/net/ethernet/cavium/thunder/pf_reg.c
>
> diff --git a/drivers/net/ethernet/cavium/thunder/pf_reg.c b/drivers/net/ethernet/cavium/thunder/pf_reg.c
Sunil>>
>From the file name 'pf_reg.c', what is PF here ?
TNS is not a SRIOV device right ?
> new file mode 100644
> index 0000000..1f95c7f
> --- /dev/null
> +++ b/drivers/net/ethernet/cavium/thunder/pf_reg.c
> @@ -0,0 +1,660 @@
> +/*
> + * Copyright (C) 2015 Cavium, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/fs.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/version.h>
> +#include <linux/proc_fs.h>
> +#include <linux/device.h>
> +#include <linux/mman.h>
> +#include <linux/uaccess.h>
> +#include <linux/delay.h>
> +#include <linux/cdev.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/firmware.h>
> +#include "pf_globals.h"
> +#include "pf_locals.h"
> +#include "tbl_access.h"
> +#include "linux/lz4.h"
> +
> +struct tns_table_s tbl_info[TNS_MAX_TABLE];
> +
> +#define TNS_TDMA_SST_ACC_CMD_ADDR 0x0000842000000270ull
> +
> +#define BAR0_START 0x842000000000
> +#define BAR0_END 0x84200000FFFF
> +#define BAR0_SIZE (64 * 1024)
> +#define BAR2_START 0x842040000000
> +#define BAR2_END 0x84207FFFFFFF
> +#define BAR2_SIZE (1024 * 1024 * 1024)
> +
> +#define NODE1_BAR0_START 0x942000000000
> +#define NODE1_BAR0_END 0x94200000FFFF
> +#define NODE1_BAR0_SIZE (64 * 1024)
> +#define NODE1_BAR2_START 0x942040000000
> +#define NODE1_BAR2_END 0x94207FFFFFFF
> +#define NODE1_BAR2_SIZE (1024 * 1024 * 1024)
Sunil>> This is absurd, why are you using hardcoded HW addresses,
why not use TNS device's PCI BARs.
> +/* Allow a max of 4 chunks for the Indirect Read/Write */
> +#define MAX_SIZE (64 * 4)
> +#define CHUNK_SIZE (64)
> +/* To protect register access */
> +spinlock_t pf_reg_lock;
> +
> +u64 iomem0;
> +u64 iomem2;
> +u8 tns_enabled;
> +u64 node1_iomem0;
> +u64 node1_iomem2;
> +u8 node1_tns;
> +int n1_tns;
Sunil>> A simple structure would have nice instead of so many global variables.
> +
> +int tns_write_register_indirect(int node_id, u64 address, u8 size,
> + u8 *kern_buffer)
> +{
> + union tns_tdma_sst_acc_cmd acccmd;
> + union tns_tdma_sst_acc_stat_t accstat;
> + union tns_acc_data data;
> + int i, j, w = 0;
> + int cnt = 0;
> + u32 *dataw = NULL;
> + int temp = 0;
> + int k = 0;
> + int chunks = 0;
> + u64 acccmd_address;
> + u64 lmem2 = 0, lmem0 = 0;
> +
> + if (size == 0 || !kern_buffer) {
> + filter_dbg(FERR, "%s data size cannot be zero\n", __func__);
> + return TNS_ERROR_INVALID_ARG;
> + }
> + if (size > MAX_SIZE) {
> + filter_dbg(FERR, "%s Max allowed size exceeded\n", __func__);
> + return TNS_ERROR_DATA_TOO_LARGE;
> + }
> + if (node_id) {
> + lmem0 = node1_iomem0;
> + lmem2 = node1_iomem2;
> + } else {
> + lmem0 = iomem0;
> + lmem2 = iomem2;
> + }
> +
> + chunks = ((size + (CHUNK_SIZE - 1)) / CHUNK_SIZE);
> + acccmd_address = (address & 0x00000000ffffffff);
> + spin_lock_bh(&pf_reg_lock);
> +
> + for (k = 0; k < chunks; k++) {
Sunil>> Why not use some proper variable names, instead of i,j,k,w,
temp e.t.c e.t.c
> + /* Should never happen */
> + if (size < 0) {
> + filter_dbg(FERR, "%s size mismatch [CHUNK %d]\n",
> + __func__, k);
> + break;
> + }
> + temp = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
> + dataw = (u32 *)(kern_buffer + (k * CHUNK_SIZE));
> + cnt = ((temp + 3) / 4);
> + data.u = 0ULL;
> + for (j = 0, i = 0; i < cnt; i++) {
> + /* Odd words go in the upper 32 bits of the data
> + * register
> + */
> + if (i & 1) {
> + data.s.upper32 = dataw[i];
> + writeq_relaxed(data.u, (void *)(lmem0 +
> + TNS_TDMA_SST_ACC_WDATX(j)));
> + data.u = 0ULL;
> + j++; /* Advance to the next data word */
> + w = 0;
> + } else {
> + /* Lower 32 bits contain words 0, 2, 4, etc. */
> + data.s.lower32 = dataw[i];
> + w = 1;
> + }
> + }
> +
> + /* If the last word was a partial (< 64 bits) then
> + * see if we need to write it.
> + */
> + if (w)
> + writeq_relaxed(data.u, (void *)(lmem0 +
> + TNS_TDMA_SST_ACC_WDATX(j)));
> +
> + acccmd.u = 0ULL;
> + acccmd.s.go = 1; /* Cleared once the request is serviced */
> + acccmd.s.size = cnt;
> + acccmd.s.addr = (acccmd_address >> 2);
> + writeq_relaxed(acccmd.u, (void *)(lmem0 +
> + TDMA_SST_ACC_CMD));
> + accstat.u = 0ULL;
> +
> + while (!accstat.s.cmd_done && !accstat.s.error)
> + accstat.u = readq_relaxed((void *)(lmem0 +
> + TDMA_SST_ACC_STAT));
> +
> + if (accstat.s.error) {
> + data.u = readq_relaxed((void *)(lmem2 +
> + TDMA_NB_INT_STAT));
> + filter_dbg(FERR, "%s Reading data from ", __func__);
> + filter_dbg(FERR, "0x%0lx chunk %d failed 0x%0lx",
> + (unsigned long)address, k,
> + (unsigned long)data.u);
> + spin_unlock_bh(&pf_reg_lock);
> + kfree(kern_buffer);
> + return TNS_ERROR_INDIRECT_WRITE;
> + }
> + /* Calculate the next offset to write */
> + acccmd_address = acccmd_address + CHUNK_SIZE;
> + size -= CHUNK_SIZE;
> + }
> + spin_unlock_bh(&pf_reg_lock);
> +
> + return 0;
> +}
> +
> +int tns_read_register_indirect(int node_id, u64 address, u8 size,
> + u8 *kern_buffer)
> +{
> + union tns_tdma_sst_acc_cmd acccmd;
> + union tns_tdma_sst_acc_stat_t accstat;
> + union tns_acc_data data;
> + int i, j, dcnt;
> + int cnt = 0;
> + u32 *dataw = NULL;
> + int temp = 0;
> + int k = 0;
> + int chunks = 0;
> + u64 acccmd_address;
> + u64 lmem2 = 0, lmem0 = 0;
> +
> + if (size == 0 || !kern_buffer) {
> + filter_dbg(FERR, "%s data size cannot be zero\n", __func__);
> + return TNS_ERROR_INVALID_ARG;
> + }
> + if (size > MAX_SIZE) {
> + filter_dbg(FERR, "%s Max allowed size exceeded\n", __func__);
> + return TNS_ERROR_DATA_TOO_LARGE;
> + }
> + if (node_id) {
> + lmem0 = node1_iomem0;
> + lmem2 = node1_iomem2;
> + } else {
> + lmem0 = iomem0;
> + lmem2 = iomem2;
> + }
> +
> + chunks = ((size + (CHUNK_SIZE - 1)) / CHUNK_SIZE);
> + acccmd_address = (address & 0x00000000ffffffff);
> + spin_lock_bh(&pf_reg_lock);
> + for (k = 0; k < chunks; k++) {
> + /* This should never happen */
> + if (size < 0) {
> + filter_dbg(FERR, "%s size mismatch [CHUNK:%d]\n",
> + __func__, k);
> + break;
> + }
> + temp = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
> + dataw = (u32 *)(kern_buffer + (k * CHUNK_SIZE));
> + cnt = ((temp + 3) / 4);
> + acccmd.u = 0ULL;
> + acccmd.s.op = 1; /* Read operation */
> + acccmd.s.size = cnt;
> + acccmd.s.addr = (acccmd_address >> 2);
> + acccmd.s.go = 1; /* Execute */
> + writeq_relaxed(acccmd.u, (void *)(lmem0 +
> + TDMA_SST_ACC_CMD));
> + accstat.u = 0ULL;
> +
> + while (!accstat.s.cmd_done && !accstat.s.error)
> + accstat.u = readq_relaxed((void *)(lmem0 +
> + TDMA_SST_ACC_STAT));
> +
> + if (accstat.s.error) {
> + data.u = readq_relaxed((void *)(lmem2 +
> + TDMA_NB_INT_STAT));
> + filter_dbg(FERR, "%s Reading data from", __func__);
> + filter_dbg(FERR, "0x%0lx chunk %d failed 0x%0lx",
> + (unsigned long)address, k,
> + (unsigned long)data.u);
> + spin_unlock_bh(&pf_reg_lock);
> + kfree(kern_buffer);
> + return TNS_ERROR_INDIRECT_READ;
> + }
> +
> + dcnt = cnt / 2;
> + if (cnt & 1)
> + dcnt++;
> + for (i = 0, j = 0; (j < dcnt) && (i < cnt); j++) {
> + data.u = readq_relaxed((void *)(lmem0 +
> + TNS_TDMA_SST_ACC_RDATX(j)));
> + dataw[i++] = data.s.lower32;
> + if (i < cnt)
> + dataw[i++] = data.s.upper32;
> + }
> + /* Calculate the next offset to read */
> + acccmd_address = acccmd_address + CHUNK_SIZE;
> + size -= CHUNK_SIZE;
> + }
> + spin_unlock_bh(&pf_reg_lock);
> + return 0;
> +}
> +
> +u64 tns_read_register(u64 start, u64 offset)
> +{
> + return readq_relaxed((void *)(start + offset));
> +}
> +
> +void tns_write_register(u64 start, u64 offset, u64 data)
> +{
> + writeq_relaxed(data, (void *)(start + offset));
> +}
> +
> +/* Check if TNS is available. If yes return 0 else 1 */
> +int is_tns_available(void)
> +{
> + union tns_tdma_cap tdma_cap;
> +
> + tdma_cap.u = tns_read_register(iomem0, TNS_TDMA_CAP_OFFSET);
> + tns_enabled = tdma_cap.s.switch_capable;
> + /* In multi-node systems, make sure TNS should be there in both nodes */
Can't node-0 TNS work with node-0 interfaces if node-1 TNS is not detected ?
> + if (nr_node_ids > 1) {
> + tdma_cap.u = tns_read_register(node1_iomem0,
> + TNS_TDMA_CAP_OFFSET);
> + if (tdma_cap.s.switch_capable)
> + n1_tns = 1;
> + }
> + tns_enabled &= tdma_cap.s.switch_capable;
> + return (!tns_enabled);
> +}
> +
> +int bist_error_check(void)
> +{
> + int fail = 0, i;
> + u64 bist_stat = 0;
> +
> + for (i = 0; i < 12; i++) {
> + bist_stat = tns_read_register(iomem0, (i * 16));
> + if (bist_stat) {
> + filter_dbg(FERR, "TNS BIST%d fail 0x%llx\n",
> + i, bist_stat);
> + fail = 1;
> + }
> + if (!n1_tns)
> + continue;
> + bist_stat = tns_read_register(node1_iomem0, (i * 16));
> + if (bist_stat) {
> + filter_dbg(FERR, "TNS(N1) BIST%d fail 0x%llx\n",
> + i, bist_stat);
> + fail = 1;
> + }
> + }
> +
> + return fail;
> +}
> +
> +int replay_indirect_trace(int node, u64 *buf_ptr, int idx)
> +{
> + union _tns_sst_config cmd = (union _tns_sst_config)(buf_ptr[idx]);
> + int remaining = cmd.cmd.run;
> + u64 io_addr;
> + int word_cnt = cmd.cmd.word_cnt;
> + int size = (word_cnt + 1) / 2;
> + u64 stride = word_cnt;
> + u64 acc_cmd = cmd.copy.do_copy;
> + u64 lmem2 = 0, lmem0 = 0;
> + union tns_tdma_sst_acc_stat_t accstat;
> + union tns_acc_data data;
> +
> + if (node) {
> + lmem0 = node1_iomem0;
> + lmem2 = node1_iomem2;
> + } else {
> + lmem0 = iomem0;
> + lmem2 = iomem2;
> + }
> +
> + if (word_cnt == 0) {
> + word_cnt = 16;
> + stride = 16;
> + size = 8;
> + } else {
> + // make stride next power of 2
Please use proper commenting, have you ran checkpatch ?
> + if (cmd.cmd.powerof2stride)
> + while ((stride & (stride - 1)) != 0)
> + stride++;
> + }
> + stride *= 4; //convert stride from 32-bit words to bytes
> +
> + do {
> + int addr_p = 1;
> + /* extract (big endian) data from the config
> + * into the data array
> + */
> + while (size > 0) {
> + io_addr = lmem0 + TDMA_SST_ACC_CMD + addr_p * 16;
> + tns_write_register(io_addr, 0, buf_ptr[idx + size]);
> + addr_p += 1;
> + size--;
> + }
> + tns_write_register((lmem0 + TDMA_SST_ACC_CMD), 0, acc_cmd);
> + /* TNS Block access registers indirectly, ran memory barrier
> + * between two writes
> + */
> + wmb();
> + /* Check for completion */
> + accstat.u = 0ULL;
> + while (!accstat.s.cmd_done && !accstat.s.error)
> + accstat.u = readq_relaxed((void *)(lmem0 +
> + TDMA_SST_ACC_STAT));
> +
> + /* Check for error, and report it */
> + if (accstat.s.error) {
> + filter_dbg(FERR, "%s data from 0x%0llx failed 0x%llx\n",
> + __func__, acc_cmd, accstat.u);
> + data.u = readq_relaxed((void *)(lmem2 +
> + TDMA_NB_INT_STAT));
> + filter_dbg(FERR, "Status 0x%llx\n", data.u);
> + }
> + /* update the address */
> + acc_cmd += stride;
> + size = (word_cnt + 1) / 2;
> + usleep_range(20, 30);
> + } while (remaining-- > 0);
> +
> + return size;
> +}
> +
> +void replay_tns_node(int node, u64 *buf_ptr, int reg_cnt)
> +{
> + int counter = 0;
> + u64 offset = 0;
> + u64 io_address;
> + int datapathmode = 1;
> + u64 lmem2 = 0, lmem0 = 0;
> +
> + if (node) {
> + lmem0 = node1_iomem0;
> + lmem2 = node1_iomem2;
> + } else {
> + lmem0 = iomem0;
> + lmem2 = iomem2;
> + }
> + for (counter = 0; counter < reg_cnt; counter++) {
> + if (buf_ptr[counter] == 0xDADADADADADADADAull) {
> + datapathmode = 1;
> + continue;
> + } else if (buf_ptr[counter] == 0xDEDEDEDEDEDEDEDEull) {
> + datapathmode = 0;
> + continue;
> + }
> + if (datapathmode == 1) {
> + if (buf_ptr[counter] >= BAR0_START &&
> + buf_ptr[counter] <= BAR0_END) {
> + offset = buf_ptr[counter] - BAR0_START;
> + io_address = lmem0 + offset;
> + } else if (buf_ptr[counter] >= BAR2_START &&
> + buf_ptr[counter] <= BAR2_END) {
> + offset = buf_ptr[counter] - BAR2_START;
> + io_address = lmem2 + offset;
> + } else {
> + filter_dbg(FERR, "%s Address 0x%llx invalid\n",
> + __func__, buf_ptr[counter]);
> + return;
> + }
> +
> + tns_write_register(io_address, 0, buf_ptr[counter + 1]);
> + /* TNS Block access registers indirectly, ran memory
> + * barrier between two writes
> + */
> + wmb();
> + counter += 1;
> + usleep_range(20, 30);
> + } else if (datapathmode == 0) {
> + int sz = replay_indirect_trace(node, buf_ptr, counter);
> +
> + counter += sz;
> + }
> + }
> +}
> +
> +int alloc_table_info(int i, struct table_static_s tbl_sdata[])
> +{
> + tbl_info[i].ddata[0].bitmap = kcalloc(BITS_TO_LONGS(tbl_sdata[i].depth),
> + sizeof(uintptr_t), GFP_KERNEL);
> + if (!tbl_info[i].ddata[0].bitmap)
> + return 1;
> +
> + if (!n1_tns)
> + return 0;
> +
> + tbl_info[i].ddata[1].bitmap = kcalloc(BITS_TO_LONGS(tbl_sdata[i].depth),
> + sizeof(uintptr_t), GFP_KERNEL);
> + if (!tbl_info[i].ddata[1].bitmap) {
> + kfree(tbl_info[i].ddata[0].bitmap);
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +void tns_replay_register_trace(const struct firmware *fw, struct device *dev)
> +{
> + int i;
> + int node = 0;
> + u8 *buffer = NULL;
> + u64 *buf_ptr = NULL;
> + struct tns_global_st *fw_header = NULL;
> + struct table_static_s tbl_sdata[TNS_MAX_TABLE];
> + size_t src_len;
> + size_t dest_len = TNS_FW_MAX_SIZE;
> + int rc;
> + u8 *fw2_buf = NULL;
> + unsigned char *decomp_dest = NULL;
> +
> + fw2_buf = (u8 *)fw->data;
> + src_len = fw->size - 8;
> +
> + decomp_dest = kcalloc((dest_len * 2), sizeof(char), GFP_KERNEL);
> + if (!decomp_dest)
> + return;
> +
> + memset(decomp_dest, 0, (dest_len * 2));
> + rc = lz4_decompress_unknownoutputsize(&fw2_buf[8], src_len, decomp_dest,
> + &dest_len);
> + if (rc) {
> + filter_dbg(FERR, "Decompress Error %d\n", rc);
> + pr_info("Uncompressed destination length %ld\n", dest_len);
> + kfree(decomp_dest);
> + return;
> + }
> + fw_header = (struct tns_global_st *)decomp_dest;
> + buffer = (u8 *)decomp_dest;
> +
> + filter_dbg(FINFO, "TNS Firmware version: %s Loading...\n",
> + fw_header->version);
> +
> + memset(tbl_info, 0x0, sizeof(tbl_info));
> + buf_ptr = (u64 *)(buffer + sizeof(struct tns_global_st));
> + memcpy(tbl_sdata, fw_header->tbl_info, sizeof(fw_header->tbl_info));
> +
> + for (i = 0; i < TNS_MAX_TABLE; i++) {
> + if (!tbl_sdata[i].valid)
> + continue;
> + memcpy(&tbl_info[i].sdata, &tbl_sdata[i],
> + sizeof(struct table_static_s));
> + if (alloc_table_info(i, tbl_sdata)) {
> + kfree(decomp_dest);
> + return;
> + }
> + }
> +
> + for (node = 0; node < nr_node_ids; node++)
> + replay_tns_node(node, buf_ptr, fw_header->reg_cnt);
> +
> + kfree(decomp_dest);
> + release_firmware(fw);
> +}
> +
> +int tns_init(const struct firmware *fw, struct device *dev)
> +{
> + int result = 0;
> + int i = 0;
> + int temp;
> + union tns_tdma_config tdma_config;
> + union tns_tdma_lmacx_config tdma_lmac_cfg;
> + u64 reg_init_val;
> +
> + spin_lock_init(&pf_reg_lock);
> +
> + /* use two regions insted of a single big mapping to save
> + * the kernel virtual space
> + */
> + iomem0 = (u64)ioremap(BAR0_START, BAR0_SIZE);
> + if (iomem0 == 0ULL) {
> + filter_dbg(FERR, "Node0 ioremap failed for BAR0\n");
> + result = -EAGAIN;
> + goto error;
> + } else {
> + filter_dbg(FINFO, "ioremap success for BAR0\n");
> + }
> +
> + if (nr_node_ids > 1) {
> + node1_iomem0 = (u64)ioremap(NODE1_BAR0_START, NODE1_BAR0_SIZE);
> + if (node1_iomem0 == 0ULL) {
> + filter_dbg(FERR, "Node1 ioremap failed for BAR0\n");
> + result = -EAGAIN;
> + goto error;
> + } else {
> + filter_dbg(FINFO, "ioremap success for BAR0\n");
> + }
> + }
> +
> + if (is_tns_available()) {
> + filter_dbg(FERR, "TNS NOT AVAILABLE\n");
> + goto error;
> + }
> +
> + if (bist_error_check()) {
> + filter_dbg(FERR, "BIST ERROR CHECK FAILED");
> + goto error;
> + }
> +
> + /* NIC0-BGX0 is TNS, NIC1-BGX1 is TNS, DISABLE BACKPRESSURE */
Sunil>> Why disable backpressure, if it's in TNS mode ?
> + reg_init_val = 0ULL;
> + pr_info("NIC Block configured in TNS/TNS mode");
> + tns_write_register(iomem0, TNS_RDMA_CONFIG_OFFSET, reg_init_val);
> + usleep_range(10, 20);
Sunil>> Why sleep after every register write ?
> + if (n1_tns) {
> + tns_write_register(node1_iomem0, TNS_RDMA_CONFIG_OFFSET,
> + reg_init_val);
> + usleep_range(10, 20);
> + }
> +
> + // Configure each LMAC with 512 credits in BYPASS mode
> + for (i = TNS_MIN_LMAC; i < (TNS_MIN_LMAC + TNS_MAX_LMAC); i++) {
> + tdma_lmac_cfg.u = 0ULL;
> + tdma_lmac_cfg.s.fifo_cdts = 0x200;
> + tns_write_register(iomem0, TNS_TDMA_LMACX_CONFIG_OFFSET(i),
> + tdma_lmac_cfg.u);
> + usleep_range(10, 20);
> + if (n1_tns) {
> + tns_write_register(node1_iomem0,
> + TNS_TDMA_LMACX_CONFIG_OFFSET(i),
> + tdma_lmac_cfg.u);
> + usleep_range(10, 20);
> + }
> + }
> +
> + //ENABLE TNS CLOCK AND CSR READS
> + temp = tns_read_register(iomem0, TNS_TDMA_CONFIG_OFFSET);
> + tdma_config.u = temp;
> + tdma_config.s.clk_2x_ena = 1;
> + tdma_config.s.clk_ena = 1;
> + tns_write_register(iomem0, TNS_TDMA_CONFIG_OFFSET, tdma_config.u);
> + if (n1_tns)
> + tns_write_register(node1_iomem0, TNS_TDMA_CONFIG_OFFSET,
> + tdma_config.u);
> +
> + temp = tns_read_register(iomem0, TNS_TDMA_CONFIG_OFFSET);
> + tdma_config.u = temp;
> + tdma_config.s.csr_access_ena = 1;
> + tns_write_register(iomem0, TNS_TDMA_CONFIG_OFFSET, tdma_config.u);
> + if (n1_tns)
> + tns_write_register(node1_iomem0, TNS_TDMA_CONFIG_OFFSET,
> + tdma_config.u);
> +
> + reg_init_val = 0ULL;
> + tns_write_register(iomem0, TNS_TDMA_RESET_CTL_OFFSET, reg_init_val);
> + if (n1_tns)
> + tns_write_register(node1_iomem0, TNS_TDMA_RESET_CTL_OFFSET,
> + reg_init_val);
> +
> + iomem2 = (u64)ioremap(BAR2_START, BAR2_SIZE);
> + if (iomem2 == 0ULL) {
> + filter_dbg(FERR, "ioremap failed for BAR2\n");
> + result = -EAGAIN;
> + goto error;
> + } else {
> + filter_dbg(FINFO, "ioremap success for BAR2\n");
> + }
> +
> + if (n1_tns) {
> + node1_iomem2 = (u64)ioremap(NODE1_BAR2_START, NODE1_BAR2_SIZE);
> + if (node1_iomem2 == 0ULL) {
> + filter_dbg(FERR, "Node1 ioremap failed for BAR2\n");
> + result = -EAGAIN;
> + goto error;
> + } else {
> + filter_dbg(FINFO, "Node1 ioremap success for BAR2\n");
> + }
> + }
> + msleep(1000);
> + //We will replay register trace to initialize TNS block
> + tns_replay_register_trace(fw, dev);
> +
> + return 0;
> +error:
> + if (iomem0 != 0)
> + iounmap((void *)iomem0);
> + if (iomem2 != 0)
> + iounmap((void *)iomem2);
> +
> + if (node1_iomem0 != 0)
> + iounmap((void *)node1_iomem0);
> + if (node1_iomem2 != 0)
> + iounmap((void *)node1_iomem2);
> +
> + return result;
> +}
> +
> +void tns_exit(void)
> +{
> + int i;
> +
> + if (iomem0 != 0)
> + iounmap((void *)iomem0);
> + if (iomem2 != 0)
> + iounmap((void *)iomem2);
> +
> + if (node1_iomem0 != 0)
> + iounmap((void *)node1_iomem0);
> + if (node1_iomem2 != 0)
> + iounmap((void *)node1_iomem2);
> +
> + for (i = 0; i < TNS_MAX_TABLE; i++) {
> + if (!tbl_info[i].sdata.valid)
> + continue;
> + kfree(tbl_info[i].ddata[0].bitmap);
> + kfree(tbl_info[i].ddata[n1_tns].bitmap);
> + }
> +}
> --
> 1.8.3.1
>
^ permalink raw reply
* [PATCH 1/7] Documentation: DT: bindings: iio: adc: add documentation for Allwinner SoCs' GPADC driver
From: Maxime Ripard @ 2016-12-21 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <61dc140a-5ef1-f55d-e749-cb816a014705@free-electrons.com>
Hi,
On Tue, Dec 20, 2016 at 04:43:58PM +0100, Quentin Schulz wrote:
> >> +
> >> +Optional properties:
> >> +(for use with thermal framework for CPU thermal throttling for example, and/or
> >> + IIO consumers)
> >> + - #thermal-sensor-cells = <0>; (see
> >> +Documentation/devicetree/bindings/thermal/thermal.txt)
> >> + - #io-channel-cells = <0>; (see
> >> +Documentation/devicetree/bindings/iio/iio-bindings.txt)
> >
> > I wouldn't list that as optional.
>
> In what sense? Do you mean you wouldn't put them here at all or you
> would require them?
I would require them.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161221/8e164a7c/attachment.sig>
^ permalink raw reply
* [RFC PATCH 0/7] ThunderX Embedded switch support
From: Sunil Kovvuri @ 2016-12-21 12:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com>
It would be easier for anyone to review if you prepare patches based on
features rather than based on modifications to files.
Thanks,
Sunil.
^ permalink raw reply
* [PATCH 5/5] ARM: dts: qcom: sd600eval: Enable riva-pil
From: Bjorn Andersson @ 2016-12-21 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221114939.19973-1-bjorn.andersson@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
My SD600eval broke, so this is untested.
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
index b7dcab28642d..8fee42901a3d 100644
--- a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
@@ -355,5 +355,12 @@
cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_HIGH>;
};
};
+
+ riva-pil at 3204000 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>;
+ };
};
};
--
2.11.0
^ permalink raw reply related
* [PATCH 4/5] ARM: dts: qcom: sd600-eval: pm8921_s2 regulator properties
From: Bjorn Andersson @ 2016-12-21 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221114939.19973-1-bjorn.andersson@linaro.org>
Add the missing properties for pm8921 smps2.
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
My SD600eval broke, so this is untested.
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
index 39ae2bc8cb08..b7dcab28642d 100644
--- a/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
@@ -74,6 +74,14 @@
bias-pull-down;
};
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+
s3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1400000>;
--
2.11.0
^ permalink raw reply related
* [PATCH 3/5] ARM: dts: qcom: apq8064-sony-yuga: Enable riva-pil
From: Bjorn Andersson @ 2016-12-21 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221114939.19973-1-bjorn.andersson@linaro.org>
Cc: John Stultz <john.stultz@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts
index ebd675ca94b4..a34ba3555454 100644
--- a/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-sony-xperia-yuga.dts
@@ -390,5 +390,12 @@
pinctrl-0 = <&sdcc3_pins>, <&sdcc3_cd_pin_a>;
};
};
+
+ riva-pil at 3204000 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>;
+ };
};
};
--
2.11.0
^ permalink raw reply related
* [PATCH 2/5] ARM: dts: qcom: apq8064: Add riva-pil node
From: Bjorn Andersson @ 2016-12-21 11:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161221114939.19973-1-bjorn.andersson@linaro.org>
Add nodes for the Riva PIL, IRIS RF module, BT and WiFI services exposed
by the Riva firmware and the related memory reserve.
Also provides pinctrl nodes for devices enabling the riva-pil.
Cc: John Stultz <john.stultz@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064-pins.dtsi | 18 +++++++++
arch/arm/boot/dts/qcom-apq8064.dtsi | 69 +++++++++++++++++++++++++++++++-
2 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/qcom-apq8064-pins.dtsi b/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
index 6b801e7e57a2..5c023e649882 100644
--- a/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064-pins.dtsi
@@ -284,4 +284,22 @@
bias-disable = <0>;
};
};
+
+ riva_fm_pin_a: riva-fm-active {
+ pins = "gpio14", "gpio15";
+ function = "riva_fm";
+ };
+
+ riva_bt_pin_a: riva-bt-active {
+ pins = "gpio16", "gpio17";
+ function = "riva_bt";
+ };
+
+ riva_wlan_pin_a: riva-wlan-active {
+ pins = "gpio64", "gpio65", "gpio66", "gpio67", "gpio68";
+ function = "riva_wlan";
+
+ drive-strength = <6>;
+ bias-pull-down;
+ };
};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 78bf155a52f3..3dc7a7aa3450 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -21,6 +21,11 @@
reg = <0x80000000 0x200000>;
no-map;
};
+
+ wcnss_mem: wcnss at 8f000000 {
+ reg = <0x8f000000 0x700000>;
+ no-map;
+ };
};
cpus {
@@ -179,7 +184,7 @@
};
clocks {
- cxo_board {
+ cxo_board: cxo_board {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <19200000>;
@@ -1419,6 +1424,68 @@
};
};
};
+
+ riva: riva-pil at 3204000 {
+ compatible = "qcom,riva-pil";
+
+ reg = <0x03200800 0x1000>, <0x03202000 0x2000>, <0x03204000 0x100>;
+ reg-names = "ccu", "dxe", "pmu";
+
+ interrupts-extended = <&intc GIC_SPI 199 IRQ_TYPE_EDGE_RISING>,
+ <&wcnss_smsm 6 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal";
+
+ memory-region = <&wcnss_mem>;
+
+ vddcx-supply = <&pm8921_s3>;
+ vddmx-supply = <&pm8921_l24>;
+ vddpx-supply = <&pm8921_s4>;
+
+ status = "disabled";
+
+ iris {
+ compatible = "qcom,wcn3660";
+
+ clocks = <&cxo_board>;
+ clock-names = "xo";
+
+ vddxo-supply = <&pm8921_l4>;
+ vddrfa-supply = <&pm8921_s2>;
+ vddpa-supply = <&pm8921_l10>;
+ vdddig-supply = <&pm8921_lvs2>;
+ };
+
+ smd-edge {
+ interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,ipc = <&l2cc 8 25>;
+ qcom,smd-edge = <6>;
+
+ label = "riva";
+
+ wcnss {
+ compatible = "qcom,wcnss";
+ qcom,smd-channels = "WCNSS_CTRL";
+
+ qcom,mmio = <&riva>;
+
+ bt {
+ compatible = "qcom,wcnss-bt";
+ };
+
+ wifi {
+ compatible = "qcom,wcnss-wlan";
+
+ interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "tx", "rx";
+
+ qcom,smem-states = <&apps_smsm 10>, <&apps_smsm 9>;
+ qcom,smem-state-names = "tx-enable", "tx-rings-empty";
+ };
+ };
+ };
+ };
};
};
#include "qcom-apq8064-pins.dtsi"
--
2.11.0
^ permalink raw reply related
* [PATCH 1/5] ARM: dts: qcom: apq8064: Add missing scm clock
From: Bjorn Andersson @ 2016-12-21 11:49 UTC (permalink / raw)
To: linux-arm-kernel
As per the device tree binding the apq8064 scm node requires the core
clock to be specified, so add this.
Cc: John Stultz <john.stultz@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
arch/arm/boot/dts/qcom-apq8064.dtsi | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index 268bd470c865..78bf155a52f3 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -303,6 +303,9 @@
firmware {
scm {
compatible = "qcom,scm-apq8064";
+
+ clocks = <&gcc CE3_CORE_CLK>;
+ clock-names = "core";
};
};
--
2.11.0
^ permalink raw reply related
* How to remove warn msg "cache: parent cpui should not be sleeping" i=1, 2, 3...
From: Jisheng Zhang @ 2016-12-21 11:37 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
I'm not sure this is a bug, when wake up from s2ram, I could get something
like:
[ 313.271464] Enabling non-boot CPUs ...
[ 313.271551] CPU1: Booted secondary processor
[ 313.271556] Detected VIPT I-cache on CPU1
[ 313.301378] cache: parent cpu1 should not be sleeping
[ 313.301504] CPU1 is up
[ 313.301582] CPU2: Booted secondary processor
[ 313.301585] Detected VIPT I-cache on CPU2
[ 313.331485] cache: parent cpu2 should not be sleeping
[ 313.331605] CPU2 is up
[ 313.331683] CPU3: Booted secondary processor
[ 313.331686] Detected VIPT I-cache on CPU3
[ 313.361599] cache: parent cpu3 should not be sleeping
[ 313.361719] CPU3 is up
This is because we call cpu_device_create() when secondary cpu is brought
online, the cpu_cache device's parent device: cpu device isn't already
resumed, all device resume will resume after secondary cores are brought
up.
What's the elegant solution to remove this warning msg?
Thanks in advance,
Jisheng
^ permalink raw reply
* [PATCH] ARM64: dts: meson-gxbb-odroidc2: fix GbE tx link breakage
From: Jerome Brunet @ 2016-12-21 11:31 UTC (permalink / raw)
To: linux-arm-kernel
OdroidC2 GbE link breaks under heavy tx transfer. This happens even if the
MAC does not enable Energy Efficient Ethernet (No Low Power state Idle on
the Tx path). The problem seems to come from the phy Rx path, entering the
LPI state.
Disabling EEE advertisement on the phy prevent this feature to be
negociated with the link partner and solve the issue.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
This patch is based on Linus recent master branch [0]
This patch depends on the series [1] which has been merged in this branch.
0: ba6d973f78eb ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net")
1: http://lkml.kernel.org/r/1480326409-25419-1-git-send-email-jbrunet at baylibre.com
Fix integration of eee-broken-modes
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index 238fbeacd330..d8933e9e9a5a 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -147,6 +147,18 @@
status = "okay";
pinctrl-0 = <ð_rgmii_pins>;
pinctrl-names = "default";
+ phy-handle = <ð_phy0>;
+
+ mdio {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ eth_phy0: ethernet-phy at 0 {
+ reg = <0>;
+ eee-broken-1000t;
+ };
+ };
};
&ir {
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 27/27] net: mvpp2: finally add the PPv2.2 compatible string
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
Now that the mvpp2 driver has been modified to accommodate the support
for PPv2.2, we can finally advertise this support by adding the
appropriate compatible string.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index d9368d6..2dc1003 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -7014,6 +7014,10 @@ static const struct of_device_id mvpp2_match[] = {
.compatible = "marvell,armada-375-pp2",
.data = (void *)MVPP21,
},
+ {
+ .compatible = "marvell,armada-7k-pp22",
+ .data = (void *)MVPP22,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, mvpp2_match);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 26/27] net: mvpp2: add support for an additional clock needed for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
The PPv2.2 variant of the network controller needs an additional
clock, the "MG clock" in order for the IP block to operate
properly. This commit adds support for this additional clock to the
driver, reworking as needed the error handling path.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index c389590..d9368d6 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -702,6 +702,7 @@ struct mvpp2 {
/* Common clocks */
struct clk *pp_clk;
struct clk *gop_clk;
+ struct clk *mg_clk;
/* List of pointers to port structures */
struct mvpp2_port **port_list;
@@ -6916,6 +6917,18 @@ static int mvpp2_probe(struct platform_device *pdev)
if (err < 0)
goto err_pp_clk;
+ if (priv->ip_version == MVPP22) {
+ priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk");
+ if (IS_ERR(priv->mg_clk)) {
+ err = PTR_ERR(priv->mg_clk);
+ goto err_gop_clk;
+ }
+
+ err = clk_prepare_enable(priv->mg_clk);
+ if (err < 0)
+ goto err_gop_clk;
+ }
+
/* Get system's tclk rate */
priv->tclk = clk_get_rate(priv->pp_clk);
@@ -6923,14 +6936,14 @@ static int mvpp2_probe(struct platform_device *pdev)
err = mvpp2_init(pdev, priv);
if (err < 0) {
dev_err(&pdev->dev, "failed to initialize controller\n");
- goto err_gop_clk;
+ goto err_mg_clk;
}
port_count = of_get_available_child_count(dn);
if (port_count == 0) {
dev_err(&pdev->dev, "no ports enabled\n");
err = -ENODEV;
- goto err_gop_clk;
+ goto err_mg_clk;
}
priv->port_list = devm_kcalloc(&pdev->dev, port_count,
@@ -6938,19 +6951,22 @@ static int mvpp2_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!priv->port_list) {
err = -ENOMEM;
- goto err_gop_clk;
+ goto err_mg_clk;
}
/* Initialize ports */
for_each_available_child_of_node(dn, port_node) {
err = mvpp2_port_probe(pdev, port_node, priv);
if (err < 0)
- goto err_gop_clk;
+ goto err_mg_clk;
}
platform_set_drvdata(pdev, priv);
return 0;
+err_mg_clk:
+ if (priv->ip_version == MVPP22)
+ clk_disable_unprepare(priv->mg_clk);
err_gop_clk:
clk_disable_unprepare(priv->gop_clk);
err_pp_clk:
@@ -6986,6 +7002,7 @@ static int mvpp2_remove(struct platform_device *pdev)
aggr_txq->descs_phys);
}
+ clk_disable_unprepare(priv->mg_clk);
clk_disable_unprepare(priv->pp_clk);
clk_disable_unprepare(priv->gop_clk);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 25/27] net: mvpp2: adapt rxq distribution to PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
In PPv2.1, we have a maximum of 8 RXQs per port, with a default of 4
RXQs per port, and we were assigning RXQs 0->3 to the first port, 4->7
to the second port, 8->11 to the third port, etc.
In PPv2.2, we have a maximum of 32 RXQs per port, and we must allocate
RXQs from the range of 32 RXQs available for each port. So port 0 must
use RXQs in the range 0->31, port 1 in the range 32->63, etc.
This commit adapts the mvpp2 to this difference between PPv2.1 and
PPv2.2:
- The constant definition MVPP2_MAX_RXQ is replaced by a new field
'max_port_rxqs' in 'struct mvpp2', which stores the maximum number of
RXQs per port. This field is initialized during ->probe() depending
on the IP version.
- MVPP2_RXQ_TOTAL_NUM is removed, and instead we calculate the total
number of RXQs by multiplying the number of ports by the maximum of
RXQs per port. This was anyway used in only one place.
- In mvpp2_port_probe(), the calculation of port->first_rxq is adjusted
to cope with the different allocation strategy between PPv2.1 and
PPv2.2. Due to this change, the 'next_first_rxq' argument of this
function is no longer needed and is removed.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index d061a1a..c389590 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -399,15 +399,9 @@
/* Maximum number of TXQs used by single port */
#define MVPP2_MAX_TXQ 8
-/* Maximum number of RXQs used by single port */
-#define MVPP2_MAX_RXQ 8
-
/* Dfault number of RXQs in use */
#define MVPP2_DEFAULT_RXQ 4
-/* Total number of RXQs available to all ports */
-#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ)
-
/* Max number of Rx descriptors */
#define MVPP2_MAX_RXD 128
@@ -728,6 +722,9 @@ struct mvpp2 {
/* HW IP Version */
enum { MVPP21, MVPP22 } ip_version;
+
+ /* Maximum number of RXQs per port */
+ unsigned int max_port_rxqs;
};
struct mvpp2_pcpu_stats {
@@ -6355,7 +6352,8 @@ static int mvpp2_port_init(struct mvpp2_port *port)
struct mvpp2_txq_pcpu *txq_pcpu;
int queue, cpu, err;
- if (port->first_rxq + rxq_number > MVPP2_RXQ_TOTAL_NUM)
+ if (port->first_rxq + rxq_number >
+ MVPP2_MAX_PORTS * priv->max_port_rxqs)
return -EINVAL;
/* Disable port */
@@ -6474,8 +6472,7 @@ static int mvpp2_port_init(struct mvpp2_port *port)
/* Ports initialization */
static int mvpp2_port_probe(struct platform_device *pdev,
struct device_node *port_node,
- struct mvpp2 *priv,
- int *next_first_rxq)
+ struct mvpp2 *priv)
{
struct device_node *phy_node;
struct mvpp2_port *port;
@@ -6533,7 +6530,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port->priv = priv;
port->id = id;
- port->first_rxq = *next_first_rxq;
+ if (priv->ip_version == MVPP21)
+ port->first_rxq = port->id * rxq_number;
+ else
+ port->first_rxq = port->id * priv->max_port_rxqs;
+
port->phy_node = phy_node;
port->phy_interface = phy_mode;
@@ -6625,8 +6626,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
}
netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
- /* Increment the first Rx queue number to be used by the next port */
- *next_first_rxq += rxq_number;
priv->port_list[id] = port;
return 0;
@@ -6772,7 +6771,7 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
u32 val;
/* Checks for hardware constraints */
- if (rxq_number % 4 || (rxq_number > MVPP2_MAX_RXQ) ||
+ if (rxq_number % 4 || (rxq_number > priv->max_port_rxqs) ||
(txq_number > MVPP2_MAX_TXQ)) {
dev_err(&pdev->dev, "invalid queue size parameter\n");
return -EINVAL;
@@ -6861,7 +6860,7 @@ static int mvpp2_probe(struct platform_device *pdev)
struct device_node *port_node;
struct mvpp2 *priv;
struct resource *res;
- int port_count, first_rxq, cpu;
+ int port_count, cpu;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(struct mvpp2), GFP_KERNEL);
@@ -6896,6 +6895,11 @@ static int mvpp2_probe(struct platform_device *pdev)
priv->cpu_base[cpu] = priv->base + cpu * addr_space_sz;
}
+ if (priv->ip_version == MVPP21)
+ priv->max_port_rxqs = 8;
+ else
+ priv->max_port_rxqs = 32;
+
priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
if (IS_ERR(priv->pp_clk))
return PTR_ERR(priv->pp_clk);
@@ -6938,9 +6942,8 @@ static int mvpp2_probe(struct platform_device *pdev)
}
/* Initialize ports */
- first_rxq = 0;
for_each_available_child_of_node(dn, port_node) {
- err = mvpp2_port_probe(pdev, port_node, priv, &first_rxq);
+ err = mvpp2_port_probe(pdev, port_node, priv);
if (err < 0)
goto err_gop_clk;
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 24/27] net: mvpp2: rework RXQ interrupt group initialization for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit adjusts how the MVPP2_ISR_RXQ_GROUP_REG register is
configured, since it changed between PPv2.1 and PPv2.2.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 45 ++++++++++++++++++++++++++++++++----
1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 6c17c7d..d061a1a 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -188,7 +188,21 @@
/* Interrupt Cause and Mask registers */
#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
#define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0
-#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
+#define MVPP21_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
+
+#define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400
+#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET 7
+
+#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+
+#define MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG 0x5404
+#define MVPP22_ISR_RXQ_SUB_GROUP_STARTQ_MASK 0x1f
+#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_MASK 0xf00
+#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET 8
+
#define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port))
#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff)
#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000)
@@ -6407,7 +6421,18 @@ static int mvpp2_port_init(struct mvpp2_port *port)
}
/* Configure Rx queue group interrupt for this port */
- mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(port->id), rxq_number);
+ if (priv->ip_version == MVPP21)
+ mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
+ rxq_number);
+ else {
+ u32 val;
+
+ val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
+
+ val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
+ }
/* Create Rx descriptor rings */
for (queue = 0; queue < rxq_number; queue++) {
@@ -6792,8 +6817,20 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
mvpp2_rx_fifo_init(priv);
/* Reset Rx queue group interrupt configuration */
- for (i = 0; i < MVPP2_MAX_PORTS; i++)
- mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(i), rxq_number);
+ for (i = 0; i < MVPP2_MAX_PORTS; i++) {
+ if (priv->ip_version == MVPP21)
+ mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(i),
+ rxq_number);
+ else {
+ u32 val;
+
+ val = (i << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
+
+ val = (rxq_number << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
+ mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
+ }
+ }
if (priv->ip_version == MVPP21)
writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 23/27] net: mvpp2: add AXI bridge initialization for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
The PPv2.2 unit is connected to an AXI bus on Armada 7K/8K, so this
commit adds the necessary initialization of the AXI bridge.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 85 ++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 9b5a7c2..6c17c7d 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -157,6 +157,34 @@
#define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2))
#define MVPP2_BASE_ADDR_ENABLE 0x4060
+/* AXI Bridge Registers */
+#define MVPP22_AXI_BM_WR_ATTR_REG 0x4100
+#define MVPP22_AXI_BM_RD_ATTR_REG 0x4104
+#define MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG 0x4110
+#define MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG 0x4114
+#define MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG 0x4118
+#define MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG 0x411c
+#define MVPP22_AXI_RX_DATA_WR_ATTR_REG 0x4120
+#define MVPP22_AXI_TX_DATA_RD_ATTR_REG 0x4130
+#define MVPP22_AXI_RD_NORMAL_CODE_REG 0x4150
+#define MVPP22_AXI_RD_SNOOP_CODE_REG 0x4154
+#define MVPP22_AXI_WR_NORMAL_CODE_REG 0x4160
+#define MVPP22_AXI_WR_SNOOP_CODE_REG 0x4164
+
+/* Values for AXI Bridge registers */
+#define MVPP22_AXI_ATTR_CACHE_OFFS 0
+#define MVPP22_AXI_ATTR_DOMAIN_OFFS 12
+
+#define MVPP22_AXI_CODE_CACHE_OFFS 0
+#define MVPP22_AXI_CODE_DOMAIN_OFFS 4
+
+#define MVPP22_AXI_CODE_CACHE_NON_CACHE 0x3
+#define MVPP22_AXI_CODE_CACHE_WR_CACHE 0x7
+#define MVPP22_AXI_CODE_CACHE_RD_CACHE 0xb
+
+#define MVPP22_AXI_CODE_DOMAIN_OUTER_DOM 2
+#define MVPP22_AXI_CODE_DOMAIN_SYSTEM 3
+
/* Interrupt Cause and Mask registers */
#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
#define MVPP2_MAX_ISR_RX_THRESHOLD 0xfffff0
@@ -6657,6 +6685,60 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv)
mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
}
+static void mvpp2_axi_init(struct mvpp2 *priv)
+{
+ u32 val, rdval, wrval;
+
+ mvpp2_write(priv, MVPP22_BM_ADDR_HIGH_RLS_REG, 0x0);
+
+ /* AXI Bridge Configuration */
+
+ rdval = MVPP22_AXI_CODE_CACHE_RD_CACHE
+ << MVPP22_AXI_ATTR_CACHE_OFFS;
+ rdval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_ATTR_DOMAIN_OFFS;
+
+ wrval = MVPP22_AXI_CODE_CACHE_WR_CACHE
+ << MVPP22_AXI_ATTR_CACHE_OFFS;
+ wrval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_ATTR_DOMAIN_OFFS;
+
+ /* BM */
+ mvpp2_write(priv, MVPP22_AXI_BM_WR_ATTR_REG, wrval);
+ mvpp2_write(priv, MVPP22_AXI_BM_RD_ATTR_REG, rdval);
+
+ /* Descriptors */
+ mvpp2_write(priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, wrval);
+ mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, wrval);
+
+ /* Buffer Data */
+ mvpp2_write(priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, wrval);
+
+ val = MVPP22_AXI_CODE_CACHE_NON_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_SYSTEM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+ mvpp2_write(priv, MVPP22_AXI_RD_NORMAL_CODE_REG, val);
+ mvpp2_write(priv, MVPP22_AXI_WR_NORMAL_CODE_REG, val);
+
+ val = MVPP22_AXI_CODE_CACHE_RD_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+
+ mvpp2_write(priv, MVPP22_AXI_RD_SNOOP_CODE_REG, val);
+
+ val = MVPP22_AXI_CODE_CACHE_WR_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+
+ mvpp2_write(priv, MVPP22_AXI_WR_SNOOP_CODE_REG, val);
+}
+
/* Initialize network controller common part HW */
static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
{
@@ -6676,6 +6758,9 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
if (dram_target_info)
mvpp2_conf_mbus_windows(dram_target_info, priv);
+ if (priv->ip_version == MVPP22)
+ mvpp2_axi_init(priv);
+
/* Disable HW PHY polling */
if (priv->ip_version == MVPP21) {
val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 22/27] net: mvpp2: handle misc PPv2.1/PPv2.2 differences
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit handles a few miscellaneous differences between PPv2.1 and
PPv2.2 in different areas, where code done for PPv2.1 doesn't apply for
PPv2.2 or needs to be adjusted (getting the MAC address, disabling PHY
polling, etc.).
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 4163b0e..9b5a7c2 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -304,6 +304,9 @@
#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+#define MVPP22_SMI_MISC_CFG_REG 0x2a204
+#define MVPP22_SMI_POLLING_EN BIT(10)
+
#define MVPP22_PORT_BASE 0x30e00
#define MVPP22_PORT_OFFSET 0x1000
@@ -5846,7 +5849,7 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev,
return 0;
}
-static void mvpp2_get_mac_address(struct mvpp2_port *port, unsigned char *addr)
+static void mvpp21_get_mac_address(struct mvpp2_port *port, unsigned char *addr)
{
u32 mac_addr_l, mac_addr_m, mac_addr_h;
@@ -6294,7 +6297,7 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
/* Driver initialization */
-static void mvpp2_port_power_up(struct mvpp2_port *port)
+static void mvpp21_port_power_up(struct mvpp2_port *port)
{
mvpp2_port_mii_set(port);
mvpp2_port_periodic_xon_disable(port);
@@ -6513,7 +6516,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
mac_from = "device tree";
ether_addr_copy(dev->dev_addr, dt_mac_addr);
} else {
- mvpp2_get_mac_address(port, hw_mac_addr);
+ if (priv->ip_version == MVPP21)
+ mvpp21_get_mac_address(port, hw_mac_addr);
if (is_valid_ether_addr(hw_mac_addr)) {
mac_from = "hardware";
ether_addr_copy(dev->dev_addr, hw_mac_addr);
@@ -6533,7 +6537,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
dev_err(&pdev->dev, "failed to init port %d\n", id);
goto err_free_stats;
}
- mvpp2_port_power_up(port);
+
+ if (priv->ip_version == MVPP21)
+ mvpp21_port_power_up(port);
port->pcpu = alloc_percpu(struct mvpp2_port_pcpu);
if (!port->pcpu) {
@@ -6671,9 +6677,15 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
mvpp2_conf_mbus_windows(dram_target_info, priv);
/* Disable HW PHY polling */
- val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
- val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
- writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ if (priv->ip_version == MVPP21) {
+ val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
+ writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ } else {
+ val = readl(priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
+ val &= ~MVPP22_SMI_POLLING_EN;
+ writel(val, priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
+ }
/* Allocate and initialize aggregated TXQs */
priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(),
@@ -6698,8 +6710,9 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
for (i = 0; i < MVPP2_MAX_PORTS; i++)
mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(i), rxq_number);
- writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
- priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
+ if (priv->ip_version == MVPP21)
+ writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
+ priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
/* Allow cache snoop when transmiting packets */
mvpp2_write(priv, MVPP2_TX_SNOOP_REG, 0x1);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 21/27] net: mvpp2: handle register mapping and access for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit adjusts the mvpp2 driver register mapping and access logic
to support PPv2.2, to handle a number of differences.
Due to how the registers are laid out in memory, the Device Tree binding
for the "reg" property is different:
- On PPv2.1, we had a first area for the common registers, and then one
area per port.
- On PPv2.2, we have a first area for the common registers, and a
second area for all the per-ports registers.
In addition, on PPv2.2, the area for the common registers is split into
so-called "address spaces" of 64 KB each. They allow to access the same
registers, but from different CPUs. Hence the introduction of cpu_base[]
in 'struct mvpp2', and the modification of the mvpp2_write() and
mvpp2_read() register accessors. For PPv2.1, the compatibility is
preserved by using an "address space" size of 0.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 78 +++++++++++++++++++++++++++++-------
1 file changed, 64 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index eb9fe86..4163b0e 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -304,6 +304,9 @@
#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+#define MVPP22_PORT_BASE 0x30e00
+#define MVPP22_PORT_OFFSET 0x1000
+
#define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff
/* Descriptor ring Macros */
@@ -631,6 +634,11 @@ enum mvpp2_prs_l3_cast {
*/
#define MVPP2_BM_SHORT_PKT_SIZE MVPP2_RX_MAX_PKT_SIZE(512)
+#define MVPP21_ADDR_SPACE_SZ 0
+#define MVPP22_ADDR_SPACE_SZ SZ_64K
+
+#define MVPP2_MAX_CPUS 4
+
enum mvpp2_bm_type {
MVPP2_BM_FREE,
MVPP2_BM_SWF_LONG,
@@ -644,6 +652,13 @@ struct mvpp2 {
/* Shared registers' base addresses */
void __iomem *base;
void __iomem *lms_base;
+ void __iomem *iface_base;
+
+ /* On PPv2.2, each CPU can access the base register through a
+ * separate address space, each 64 KB apart from each
+ * other.
+ */
+ void __iomem *cpu_base[MVPP2_MAX_CPUS];
/* Common clocks */
struct clk *pp_clk;
@@ -1021,12 +1036,21 @@ static int txq_number = MVPP2_MAX_TXQ;
static void mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data)
{
- writel(data, priv->base + offset);
+ int cpu = get_cpu();
+
+ writel(data, priv->cpu_base[cpu] + offset);
+ put_cpu();
}
static u32 mvpp2_read(struct mvpp2 *priv, u32 offset)
{
- return readl(priv->base + offset);
+ int cpu = get_cpu();
+ u32 val;
+
+ val = readl(priv->cpu_base[cpu] + offset);
+ put_cpu();
+
+ return val;
}
static dma_addr_t mvpp2_txdesc_phys_addr_get(struct mvpp2_port *port,
@@ -6408,7 +6432,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
u32 id;
int features;
int phy_mode;
- int priv_common_regs_num = 2;
int err, i, cpu;
dev = alloc_etherdev_mqs(sizeof(struct mvpp2_port), txq_number,
@@ -6458,12 +6481,24 @@ static int mvpp2_port_probe(struct platform_device *pdev,
port->phy_node = phy_node;
port->phy_interface = phy_mode;
- res = platform_get_resource(pdev, IORESOURCE_MEM,
- priv_common_regs_num + id);
- port->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(port->base)) {
- err = PTR_ERR(port->base);
- goto err_free_irq;
+ if (priv->ip_version == MVPP21) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + id);
+ port->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->base)) {
+ err = PTR_ERR(port->base);
+ goto err_free_irq;
+ }
+ } else {
+ u32 gop_id;
+
+ if (of_property_read_u32(port_node, "gop-port-id", &gop_id)) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "missing gop-port-id value\n");
+ goto err_free_irq;
+ }
+
+ port->base = priv->iface_base + MVPP22_PORT_BASE +
+ gop_id * MVPP22_PORT_OFFSET;
}
/* Alloc per-cpu stats */
@@ -6691,7 +6726,7 @@ static int mvpp2_probe(struct platform_device *pdev)
struct device_node *port_node;
struct mvpp2 *priv;
struct resource *res;
- int port_count, first_rxq;
+ int port_count, first_rxq, cpu;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(struct mvpp2), GFP_KERNEL);
@@ -6706,10 +6741,25 @@ static int mvpp2_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->lms_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(priv->lms_base))
- return PTR_ERR(priv->lms_base);
+ if (priv->ip_version == MVPP21) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->lms_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->lms_base))
+ return PTR_ERR(priv->lms_base);
+ } else {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->iface_base))
+ return PTR_ERR(priv->iface_base);
+ }
+
+ for_each_present_cpu(cpu) {
+ u32 addr_space_sz;
+
+ addr_space_sz = (priv->ip_version == MVPP21 ?
+ MVPP21_ADDR_SPACE_SZ : MVPP22_ADDR_SPACE_SZ);
+ priv->cpu_base[cpu] = priv->base + cpu * addr_space_sz;
+ }
priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
if (IS_ERR(priv->pp_clk))
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 20/27] net: mvpp2: adjust mvpp2_{rxq, txq}_init for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
In PPv2.2, the MVPP2_RXQ_DESC_ADDR_REG and MVPP2_TXQ_DESC_ADDR_REG
registers have a slightly different layout, because they need to contain
a 64-bit address for the RX and TX descriptor arrays. This commit
adjusts those functions accordingly.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 1394ed9..eb9fe86 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -102,6 +102,7 @@
/* Descriptor Manager Top Registers */
#define MVPP2_RXQ_NUM_REG 0x2040
#define MVPP2_RXQ_DESC_ADDR_REG 0x2044
+#define MVPP22_DESC_ADDR_OFFS 8
#define MVPP2_RXQ_DESC_SIZE_REG 0x2048
#define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0
#define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq))
@@ -143,6 +144,7 @@
#define MVPP2_TXQ_RSVD_CLR_REG 0x20b8
#define MVPP2_TXQ_RSVD_CLR_OFFSET 16
#define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu))
+#define MVPP22_AGGR_TXQ_DESC_ADDR_OFFS 8
#define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu))
#define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0
#define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu))
@@ -4769,6 +4771,8 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
int desc_num, int cpu,
struct mvpp2 *priv)
{
+ u32 txq_phys;
+
/* Allocate memory for TX descriptors */
aggr_txq->descs = dma_alloc_coherent(&pdev->dev,
desc_num * MVPP2_DESC_ALIGNED_SIZE,
@@ -4782,10 +4786,16 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev,
aggr_txq->next_desc_to_proc = mvpp2_read(priv,
MVPP2_AGGR_TXQ_INDEX_REG(cpu));
- /* Set Tx descriptors queue starting address */
- /* indirect access */
- mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu),
- aggr_txq->descs_phys);
+ /* Set Tx descriptors queue starting address indirect
+ * access
+ */
+ if (priv->ip_version == MVPP21)
+ txq_phys = aggr_txq->descs_phys;
+ else
+ txq_phys = aggr_txq->descs_phys >>
+ MVPP22_AGGR_TXQ_DESC_ADDR_OFFS;
+
+ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_phys);
mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), desc_num);
return 0;
@@ -4796,6 +4806,8 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
struct mvpp2_rx_queue *rxq)
{
+ u32 rxq_phys;
+
rxq->size = port->rx_ring_size;
/* Allocate memory for RX descriptors */
@@ -4812,7 +4824,11 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
/* Set Rx descriptors queue starting address - indirect access */
mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id);
- mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq->descs_phys);
+ if (port->priv->ip_version == MVPP21)
+ rxq_phys = rxq->descs_phys;
+ else
+ rxq_phys = rxq->descs_phys >> MVPP22_DESC_ADDR_OFFS;
+ mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq_phys);
mvpp2_write(port->priv, MVPP2_RXQ_DESC_SIZE_REG, rxq->size);
mvpp2_write(port->priv, MVPP2_RXQ_INDEX_REG, 0);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 19/27] net: mvpp2: adapt mvpp2_defaults_set() to PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit modifies the mvpp2_defaults_set() function to not do the
loopback and FIFO threshold initialization, which are not needed for
PPv2.2.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index dd44065..1394ed9 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -4205,16 +4205,18 @@ static void mvpp2_defaults_set(struct mvpp2_port *port)
{
int tx_port_num, val, queue, ptxq, lrxq;
- /* Configure port to loopback if needed */
- if (port->flags & MVPP2_F_LOOPBACK)
- mvpp2_port_loopback_set(port);
-
- /* Update TX FIFO MIN Threshold */
- val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
- val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
- /* Min. TX threshold must be less than minimal packet length */
- val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2);
- writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ if (port->priv->ip_version == MVPP21) {
+ /* Configure port to loopback if needed */
+ if (port->flags & MVPP2_F_LOOPBACK)
+ mvpp2_port_loopback_set(port);
+
+ /* Update TX FIFO MIN Threshold */
+ val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
+ /* Min. TX threshold must be less than minimal packet length */
+ val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2);
+ writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ }
/* Disable Legacy WRR, Disable EJP, Release from reset */
tx_port_num = mvpp2_egress_port(port);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 18/27] net: mvpp2: adapt the mvpp2_rxq_*_pool_set functions to PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
The MVPP2_RXQ_CONFIG_REG register has a slightly different layout
between PPv2.1 and PPv2.2, so this commit adapts the functions modifying
this register to accommodate for both the PPv2.1 and PPv2.2 cases.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 32 ++++++++++++++++++++------------
1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 772c384..dd44065 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -50,9 +50,11 @@
#define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff
#define MVPP2_SNOOP_BUF_HDR_MASK BIT(9)
#define MVPP2_RXQ_POOL_SHORT_OFFS 20
-#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000
+#define MVPP21_RXQ_POOL_SHORT_MASK 0x700000
+#define MVPP22_RXQ_POOL_SHORT_MASK 0xf00000
#define MVPP2_RXQ_POOL_LONG_OFFS 24
-#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000
+#define MVPP21_RXQ_POOL_LONG_MASK 0x7000000
+#define MVPP22_RXQ_POOL_LONG_MASK 0xf000000
#define MVPP2_RXQ_PACKET_OFFSET_OFFS 28
#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000
#define MVPP2_RXQ_DISABLE_MASK BIT(31)
@@ -3762,17 +3764,20 @@ static int mvpp2_bm_init(struct platform_device *pdev, struct mvpp2 *priv)
static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port,
int lrxq, int long_pool)
{
- u32 val;
+ u32 val, mask;
int prxq;
/* Get queue physical ID */
prxq = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
- val &= ~MVPP2_RXQ_POOL_LONG_MASK;
- val |= ((long_pool << MVPP2_RXQ_POOL_LONG_OFFS) &
- MVPP2_RXQ_POOL_LONG_MASK);
+ if (port->priv->ip_version == MVPP21)
+ mask = MVPP21_RXQ_POOL_LONG_MASK;
+ else
+ mask = MVPP22_RXQ_POOL_LONG_MASK;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
+ val &= ~mask;
+ val |= (long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & mask;
mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
}
@@ -3780,17 +3785,20 @@ static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port,
static void mvpp2_rxq_short_pool_set(struct mvpp2_port *port,
int lrxq, int short_pool)
{
- u32 val;
+ u32 val, mask;
int prxq;
/* Get queue physical ID */
prxq = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
- val &= ~MVPP2_RXQ_POOL_SHORT_MASK;
- val |= ((short_pool << MVPP2_RXQ_POOL_SHORT_OFFS) &
- MVPP2_RXQ_POOL_SHORT_MASK);
+ if (port->priv->ip_version == MVPP21)
+ mask = MVPP21_RXQ_POOL_SHORT_MASK;
+ else
+ mask = MVPP22_RXQ_POOL_SHORT_MASK;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
+ val &= ~mask;
+ val |= (short_pool << MVPP2_RXQ_POOL_SHORT_OFFS) & mask;
mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 17/27] net: mvpp2: adjust the allocation/free of BM pools for PPv2.2
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit adjusts the allocation and freeing of BM pools to support
PPv2.2. This involves:
- Checking that the number of buffer pointers is a multiple of 16, as
required by the hardware.
- Adjusting the size of the DMA coherent area allocated for buffer
pointers. Indeed, PPv2.2 needs space for 2 pointers of 64-bits per
buffer, as opposed to 2 pointers of 32-bits per buffer in
PPv2.1. The size in bytes is now stored in a new field of the
mvpp2_bm_pool structure.
- On PPv2.2, the 32 high order bits of the BM pointer area physical
address must be programmed in the MVPP2_BM_HIGH_BASE_REG register.
- On PPv2.2, getting the physical and virtual address of each buffer
requires reading the MVPP2_BM_ADDR_HIGH_ALLOC to get the high order
bits of those addresses. A new utility function
mvpp2_bm_bufs_get_addrs() is introduced to handle this.
- On PPv2.2, releasing a buffer requires writing the high order 32 bits
of the physical address to MVPP2_BM_PHY_VIRT_HIGH_RLS_REG. We no
longer need to write the virtual address to MVPP2_BM_VIRT_RLS_REG.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 97 ++++++++++++++++++++++++++++++------
1 file changed, 82 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 41d7bed..772c384 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -208,17 +208,28 @@
#define MVPP2_BM_BPPE_FULL_MASK BIT(3)
#define MVPP2_BM_AVAILABLE_BP_LOW_MASK BIT(4)
#define MVPP2_BM_INTR_MASK_REG(pool) (0x6280 + ((pool) * 4))
+#define MVPP2_BM_HIGH_BASE_REG 0x6310
+#define MVPP2_BM_HIGH_BASE_MASK 0xff
#define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4))
#define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0)
#define MVPP2_BM_VIRT_ALLOC_REG 0x6440
+#define MVPP2_BM_ADDR_HIGH_ALLOC 0x6444
+#define MVPP2_BM_ADDR_HIGH_PHYS_MASK 0xff
+#define MVPP2_BM_ADDR_HIGH_VIRT_MASK 0xff00
+#define MVPP2_BM_ADDR_HIGH_VIRT_SHIFT 8
#define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4))
#define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0)
#define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1)
#define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2)
#define MVPP2_BM_VIRT_RLS_REG 0x64c0
-#define MVPP2_BM_MC_RLS_REG 0x64c4
+#define MVPP21_BM_MC_RLS_REG 0x64c4
#define MVPP2_BM_MC_ID_MASK 0xfff
#define MVPP2_BM_FORCE_RELEASE_MASK BIT(12)
+#define MVPP22_BM_ADDR_HIGH_RLS_REG 0x64c4
+#define MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK 0xff
+#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
+#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8
+#define MVPP22_BM_MC_RLS_REG 0x64d4
/* TX Scheduler registers */
#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000
@@ -957,6 +968,8 @@ struct mvpp2_bm_pool {
/* Buffer Pointers Pool External (BPPE) size */
int size;
+ /* BPPE size in bytes */
+ int size_bytes;
/* Number of buffers for this pool */
int buf_num;
/* Pool buffer size */
@@ -3558,11 +3571,23 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev,
struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool, int size)
{
- int size_bytes;
u32 val;
- size_bytes = sizeof(u32) * size;
- bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, size_bytes,
+ /* Number of buffer pointers must be a multiple of 16, as per
+ * hardware constraints
+ */
+ if (!IS_ALIGNED(size, 16))
+ return -EINVAL;
+
+ /* PPv2.1 needs 8 bytes per buffer pointer, PPv2.2 needs 16
+ * bytes per buffer pointer
+ */
+ if (priv->ip_version == MVPP21)
+ bm_pool->size_bytes = 2 * sizeof(u32) * size;
+ else
+ bm_pool->size_bytes = 2 * sizeof(u64) * size;
+
+ bm_pool->virt_addr = dma_alloc_coherent(&pdev->dev, bm_pool->size_bytes,
&bm_pool->phys_addr,
GFP_KERNEL);
if (!bm_pool->virt_addr)
@@ -3570,15 +3595,24 @@ static int mvpp2_bm_pool_create(struct platform_device *pdev,
if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr,
MVPP2_BM_POOL_PTR_ALIGN)) {
- dma_free_coherent(&pdev->dev, size_bytes, bm_pool->virt_addr,
- bm_pool->phys_addr);
+ dma_free_coherent(&pdev->dev, bm_pool->size_bytes,
+ bm_pool->virt_addr, bm_pool->phys_addr);
dev_err(&pdev->dev, "BM pool %d is not %d bytes aligned\n",
bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN);
return -ENOMEM;
}
mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id),
- bm_pool->phys_addr);
+ lower_32_bits(bm_pool->phys_addr));
+ /* On PPv2.2, program the high order bits of the base address */
+ if (priv->ip_version == MVPP22) {
+ if (sizeof(dma_addr_t) == 8)
+ val = upper_32_bits(bm_pool->phys_addr) &
+ MVPP2_BM_HIGH_BASE_MASK;
+ else
+ val = 0;
+ mvpp2_write(priv, MVPP2_BM_HIGH_BASE_REG, val);
+ }
mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size);
val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id));
@@ -3606,6 +3640,27 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
mvpp2_write(priv, MVPP2_POOL_BUF_SIZE_REG(bm_pool->id), val);
}
+static void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv,
+ struct mvpp2_bm_pool *bm_pool,
+ dma_addr_t *paddr, unsigned long *vaddr)
+{
+ *paddr = mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+ *vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (priv->ip_version == MVPP22) {
+ u32 val;
+ u32 paddr_highbits;
+
+ val = mvpp2_read(priv, MVPP2_BM_ADDR_HIGH_ALLOC);
+ paddr_highbits = (val & MVPP2_BM_ADDR_HIGH_PHYS_MASK);
+
+ *paddr |= (dma_addr_t)paddr_highbits << 32;
+ *vaddr = (unsigned long)phys_to_virt(dma_to_phys(dev, *paddr));
+ }
+#endif
+}
+
/* Free all buffers from the pool */
static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool)
@@ -3616,10 +3671,8 @@ static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
dma_addr_t buf_phys_addr;
unsigned long vaddr;
- /* Get buffer virtual address (indirect access) */
- buf_phys_addr = mvpp2_read(priv,
- MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
- vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG);
+ mvpp2_bm_bufs_get_addrs(dev, priv, bm_pool,
+ &buf_phys_addr, &vaddr);
dma_unmap_single(dev, buf_phys_addr,
bm_pool->buf_size, DMA_FROM_DEVICE);
@@ -3651,7 +3704,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
val |= MVPP2_BM_STOP_MASK;
mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val);
- dma_free_coherent(&pdev->dev, sizeof(u32) * bm_pool->size,
+ dma_free_coherent(&pdev->dev, bm_pool->size_bytes,
bm_pool->virt_addr,
bm_pool->phys_addr);
return 0;
@@ -3787,8 +3840,19 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
dma_addr_t buf_phys_addr,
unsigned long buf_virt_addr)
{
- mvpp2_write(port->priv, MVPP2_BM_VIRT_RLS_REG, buf_virt_addr);
- mvpp2_write(port->priv, MVPP2_BM_PHY_RLS_REG(pool), buf_phys_addr);
+#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT)
+ u32 val;
+
+ val = upper_32_bits(buf_phys_addr) & MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK;
+ val |= (upper_32_bits(buf_virt_addr) &
+ MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK)
+ << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT;
+ mvpp2_write(port->priv, MVPP22_BM_ADDR_HIGH_RLS_REG, val);
+#endif
+ mvpp2_write(port->priv, MVPP2_BM_VIRT_RLS_REG,
+ lower_32_bits(buf_virt_addr));
+ mvpp2_write(port->priv, MVPP2_BM_PHY_RLS_REG(pool),
+ lower_32_bits(buf_phys_addr));
}
/* Release multicast buffer */
@@ -3800,7 +3864,10 @@ static void mvpp2_bm_pool_mc_put(struct mvpp2_port *port, int pool,
u32 val = 0;
val |= (mc_id & MVPP2_BM_MC_ID_MASK);
- mvpp2_write(port->priv, MVPP2_BM_MC_RLS_REG, val);
+ if (port->priv->ip_version == MVPP21)
+ mvpp2_write(port->priv, MVPP21_BM_MC_RLS_REG, val);
+ else
+ mvpp2_write(port->priv, MVPP22_BM_MC_RLS_REG, val);
mvpp2_bm_pool_put(port, pool,
buf_phys_addr | MVPP2_BM_PHY_RLS_MC_BUFF_MASK,
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 16/27] net: mvpp2: introduce PPv2.2 HW descriptors and adapt accessors
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
This commit adds the definition of the PPv2.2 HW descriptors, adjusts
the mvpp2_tx_desc and mvpp2_rx_desc structures accordingly, and adapts
the accessors to work on both PPv2.1 and PPv2.2.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 109 +++++++++++++++++++++++++++++++----
1 file changed, 98 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 1086b36..41d7bed 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -773,18 +773,42 @@ struct mvpp21_rx_desc {
u32 reserved8;
};
+/* HW TX descriptor for PPv2.2 */
+struct mvpp22_tx_desc {
+ u32 command;
+ u8 packet_offset;
+ u8 phys_txq;
+ u16 data_size;
+ u64 reserved1;
+ u64 buf_phys_addr_ptp;
+ u64 buf_cookie_misc;
+};
+
+/* HW RX descriptor for PPv2.2 */
+struct mvpp22_rx_desc {
+ u32 status;
+ u16 reserved1;
+ u16 data_size;
+ u32 reserved2;
+ u32 reserved3;
+ u64 buf_phys_addr_key_hash;
+ u64 buf_cookie_misc;
+};
+
/* Opaque type used by the driver to manipulate the HW TX and RX
* descriptors
*/
struct mvpp2_tx_desc {
union {
struct mvpp21_tx_desc pp21;
+ struct mvpp22_tx_desc pp22;
};
};
struct mvpp2_rx_desc {
union {
struct mvpp21_rx_desc pp21;
+ struct mvpp22_rx_desc pp22;
};
};
@@ -991,72 +1015,135 @@ static u32 mvpp2_read(struct mvpp2 *priv, u32 offset)
static dma_addr_t mvpp2_txdesc_phys_addr_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc)
{
- return tx_desc->pp21.buf_phys_addr;
+ if (port->priv->ip_version == MVPP21)
+ return tx_desc->pp21.buf_phys_addr;
+ else
+ return tx_desc->pp22.buf_phys_addr_ptp & DMA_BIT_MASK(40);
}
static void mvpp2_txdesc_phys_addr_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
dma_addr_t phys_addr)
{
- tx_desc->pp21.buf_phys_addr = phys_addr;
+ if (port->priv->ip_version == MVPP21) {
+ tx_desc->pp21.buf_phys_addr = phys_addr;
+ } else {
+ u64 val = (u64)phys_addr;
+
+ tx_desc->pp22.buf_phys_addr_ptp &= ~DMA_BIT_MASK(40);
+ tx_desc->pp22.buf_phys_addr_ptp |= val;
+ }
}
static size_t mvpp2_txdesc_size_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc)
{
- return tx_desc->pp21.data_size;
+ if (port->priv->ip_version == MVPP21)
+ return tx_desc->pp21.data_size;
+ else
+ return tx_desc->pp22.data_size;
}
static void mvpp2_txdesc_size_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
size_t size)
{
- tx_desc->pp21.data_size = size;
+ if (port->priv->ip_version == MVPP21)
+ tx_desc->pp21.data_size = size;
+ else
+ tx_desc->pp22.data_size = size;
}
static void mvpp2_txdesc_txq_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int txq)
{
- tx_desc->pp21.phys_txq = txq;
+ if (port->priv->ip_version == MVPP21)
+ tx_desc->pp21.phys_txq = txq;
+ else
+ tx_desc->pp22.phys_txq = txq;
}
static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int command)
{
- tx_desc->pp21.command = command;
+ if (port->priv->ip_version == MVPP21)
+ tx_desc->pp21.command = command;
+ else
+ tx_desc->pp22.command = command;
}
static void mvpp2_txdesc_offset_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int offset)
{
- tx_desc->pp21.packet_offset = offset;
+ if (port->priv->ip_version == MVPP21)
+ tx_desc->pp21.packet_offset = offset;
+ else
+ tx_desc->pp22.packet_offset = offset;
}
static dma_addr_t mvpp2_rxdesc_phys_addr_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->pp21.buf_phys_addr;
+ if (port->priv->ip_version == MVPP21)
+ return rx_desc->pp21.buf_phys_addr;
+ else
+ return rx_desc->pp22.buf_phys_addr_key_hash & DMA_BIT_MASK(40);
}
static unsigned long mvpp2_rxdesc_virt_addr_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->pp21.buf_cookie;
+ /* PPv2.1 can only be used on 32 bits architectures, and there
+ * are 32 bits in buf_cookie which are enough to store the
+ * full virtual address, so things are easy.
+ */
+ if (port->priv->ip_version == MVPP21) {
+ return rx_desc->pp21.buf_cookie;
+ } else {
+ /* On PPv2.2, the situation is more complicated,
+ * because there is only 40 bits to store the virtual
+ * address, which is not sufficient. So on 64 bits
+ * systems, we use phys_to_virt() to get the virtual
+ * address from the physical address, which is fine
+ * because the kernel linear mapping includes the
+ * entire 40 bits physical address space. On 32 bits
+ * systems however, we can't use phys_to_virt(), but
+ * since virtual addresses are 32 bits only, there is
+ * enough space in the RX descriptor for the full
+ * virtual address.
+ */
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ dma_addr_t dma_addr =
+ rx_desc->pp22.buf_phys_addr_key_hash & DMA_BIT_MASK(40);
+ phys_addr_t phys_addr =
+ dma_to_phys(port->dev->dev.parent, dma_addr);
+
+ return (unsigned long)phys_to_virt(phys_addr);
+#else
+ return rx_desc->pp22.buf_cookie_misc & DMA_BIT_MASK(40);
+#endif
+ }
}
static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->pp21.data_size;
+ if (port->priv->ip_version == MVPP21)
+ return rx_desc->pp21.data_size;
+ else
+ return rx_desc->pp22.data_size;
}
static u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->pp21.status;
+ if (port->priv->ip_version == MVPP21)
+ return rx_desc->pp21.status;
+ else
+ return rx_desc->pp22.status;
}
static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
--
2.7.4
^ permalink raw reply related
* [PATCH net-next 15/27] net: mvpp2: introduce an intermediate union for the TX/RX descriptors
From: Thomas Petazzoni @ 2016-12-21 11:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1482318994-23488-1-git-send-email-thomas.petazzoni@free-electrons.com>
Since the format of the HW descriptors is different between PPv2.1 and
PPv2.2, this commit introduces an intermediate union, with for now
only the PPv2.1 descriptors. The bulk of the driver code only
manipulates opaque mvpp2_tx_desc and mvpp2_rx_desc pointers, and the
descriptors can only be accessed and modified through the accessor
functions. A follow-up commit will add the descriptor definitions for
PPv2.2.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 43 +++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index af00405..1086b36 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -745,7 +745,8 @@ struct mvpp2_port {
#define MVPP2_RXD_L3_IP6 BIT(30)
#define MVPP2_RXD_BUF_HDR BIT(31)
-struct mvpp2_tx_desc {
+/* HW TX descriptor for PPv2.1 */
+struct mvpp21_tx_desc {
u32 command; /* Options used by HW for packet transmitting.*/
u8 packet_offset; /* the offset from the buffer beginning */
u8 phys_txq; /* destination queue ID */
@@ -756,7 +757,8 @@ struct mvpp2_tx_desc {
u32 reserved2; /* reserved (for future use) */
};
-struct mvpp2_rx_desc {
+/* HW RX descriptor for PPv2.1 */
+struct mvpp21_rx_desc {
u32 status; /* info about received packet */
u16 reserved1; /* parser_info (for future use, PnC) */
u16 data_size; /* size of received packet in bytes */
@@ -771,6 +773,21 @@ struct mvpp2_rx_desc {
u32 reserved8;
};
+/* Opaque type used by the driver to manipulate the HW TX and RX
+ * descriptors
+ */
+struct mvpp2_tx_desc {
+ union {
+ struct mvpp21_tx_desc pp21;
+ };
+};
+
+struct mvpp2_rx_desc {
+ union {
+ struct mvpp21_rx_desc pp21;
+ };
+};
+
struct mvpp2_txq_pcpu_buf {
/* Transmitted SKB */
struct sk_buff *skb;
@@ -974,72 +991,72 @@ static u32 mvpp2_read(struct mvpp2 *priv, u32 offset)
static dma_addr_t mvpp2_txdesc_phys_addr_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc)
{
- return tx_desc->buf_phys_addr;
+ return tx_desc->pp21.buf_phys_addr;
}
static void mvpp2_txdesc_phys_addr_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
dma_addr_t phys_addr)
{
- tx_desc->buf_phys_addr = phys_addr;
+ tx_desc->pp21.buf_phys_addr = phys_addr;
}
static size_t mvpp2_txdesc_size_get(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc)
{
- return tx_desc->data_size;
+ return tx_desc->pp21.data_size;
}
static void mvpp2_txdesc_size_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
size_t size)
{
- tx_desc->data_size = size;
+ tx_desc->pp21.data_size = size;
}
static void mvpp2_txdesc_txq_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int txq)
{
- tx_desc->phys_txq = txq;
+ tx_desc->pp21.phys_txq = txq;
}
static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int command)
{
- tx_desc->command = command;
+ tx_desc->pp21.command = command;
}
static void mvpp2_txdesc_offset_set(struct mvpp2_port *port,
struct mvpp2_tx_desc *tx_desc,
unsigned int offset)
{
- tx_desc->packet_offset = offset;
+ tx_desc->pp21.packet_offset = offset;
}
static dma_addr_t mvpp2_rxdesc_phys_addr_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->buf_phys_addr;
+ return rx_desc->pp21.buf_phys_addr;
}
static unsigned long mvpp2_rxdesc_virt_addr_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->buf_cookie;
+ return rx_desc->pp21.buf_cookie;
}
static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->data_size;
+ return rx_desc->pp21.data_size;
}
static u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port,
struct mvpp2_rx_desc *rx_desc)
{
- return rx_desc->status;
+ return rx_desc->pp21.status;
}
static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox