[barefoot] Added Newport platform support (#3709)

[barefoot] Added Newport platform support

Signed-off-by: Andriy Kokhan <akokhan@barefootnetworks.com>
This commit is contained in:
Andriy Kokhan 2019-11-07 04:54:05 +02:00 committed by lguohan
parent 95466c3ab7
commit 3b51cec9a3
43 changed files with 3951 additions and 0 deletions

View File

@ -0,0 +1 @@
newport t1

View File

@ -0,0 +1 @@
CONSOLE_SPEED=57600

View File

@ -0,0 +1,2 @@
{%- set default_topo = 't0' %}
{%- include 'buffers_config.j2' %}

View File

@ -0,0 +1,71 @@
{% set default_cable = '5m' %}
{% set ingress_lossless_pool_size = '4194304' %}
{% set ingress_lossy_pool_size = '7340032' %}
{% set egress_lossless_pool_size = '16777152' %}
{% set egress_lossy_pool_size = '7340032' %}
{%- macro generate_port_lists(PORT_ALL) %}
{# Generate list of ports #}
{%- for port_idx in range(0,32) %}
{%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %}
{%- endfor %}
{%- endmacro %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "{{ ingress_lossless_pool_size }}",
"type": "ingress",
"mode": "dynamic",
"xoff": "2867200"
},
"ingress_lossy_pool": {
"size": "{{ ingress_lossy_pool_size }}",
"type": "ingress",
"mode": "dynamic"
},
"egress_lossless_pool": {
"size": "{{ egress_lossless_pool_size }}",
"type": "egress",
"mode": "dynamic"
},
"egress_lossy_pool": {
"size": "{{ egress_lossy_pool_size }}",
"type": "egress",
"mode": "dynamic"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"dynamic_th":"7"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
},
"q_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
}
},
{%- endmacro %}
{%- macro generate_queue_buffers(port_names) %}
"BUFFER_QUEUE": {
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
},
"{{ port_names }}|0-1": {
"profile" : "[BUFFER_PROFILE|q_lossy_profile]"
}
}
{%- endmacro %}

View File

@ -0,0 +1,71 @@
{% set default_cable = '5m' %}
{% set ingress_lossless_pool_size = '2097152' %}
{% set ingress_lossy_pool_size = '5242880' %}
{% set egress_lossless_pool_size = '16777152' %}
{% set egress_lossy_pool_size = '5242880' %}
{%- macro generate_port_lists(PORT_ALL) %}
{# Generate list of ports #}
{%- for port_idx in range(0,32) %}
{%- if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{%- endif %}
{%- endfor %}
{%- endmacro %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "{{ ingress_lossless_pool_size }}",
"type": "ingress",
"mode": "dynamic",
"xoff": "2867200"
},
"ingress_lossy_pool": {
"size": "{{ ingress_lossy_pool_size }}",
"type": "ingress",
"mode": "dynamic"
},
"egress_lossless_pool": {
"size": "{{ egress_lossless_pool_size }}",
"type": "egress",
"mode": "dynamic"
},
"egress_lossy_pool": {
"size": "{{ egress_lossy_pool_size }}",
"type": "egress",
"mode": "dynamic"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"dynamic_th":"7"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
},
"q_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossy_pool]",
"size":"4096",
"dynamic_th":"3"
}
},
{%- endmacro %}
{%- macro generate_queue_buffers(port_names) %}
"BUFFER_QUEUE": {
"{{ port_names }}|3-4": {
"profile" : "[BUFFER_PROFILE|egress_lossless_profile]"
},
"{{ port_names }}|0-1": {
"profile" : "[BUFFER_PROFILE|q_lossy_profile]"
}
}
{%- endmacro %}

View File

@ -0,0 +1,20 @@
# PG lossless profiles.
# speed cable size xon xoff threshold
10000 5m 34816 18432 16384 7
25000 5m 34816 18432 16384 7
40000 5m 34816 18432 16384 7
50000 5m 34816 18432 16384 7
100000 5m 36864 18432 18432 7
400000 5m 36864 18432 18432 7
10000 40m 36864 18432 18432 7
25000 40m 39936 18432 21504 7
40000 40m 41984 18432 23552 7
50000 40m 41984 18432 23552 7
100000 40m 54272 18432 35840 7
400000 40m 54272 18432 35840 7
10000 300m 49152 18432 30720 7
25000 300m 71680 18432 53248 7
40000 300m 94208 18432 75776 7
50000 300m 94208 18432 75776 7
100000 300m 184320 18432 165888 7
400000 300m 184320 18432 165888 7

View File

@ -0,0 +1,33 @@
# name lanes alias index speed autoneg fec
Ethernet0 0,1,2,3,4,5,6,7 Ethernet0 1 400000 0 rs
Ethernet8 8,9,10,11,12,13,14,15 Ethernet8 2 400000 0 rs
Ethernet16 16,17,18,19,20,21,22,23 Ethernet16 3 400000 0 rs
Ethernet24 24,25,26,27,28,29,30,31 Ethernet24 4 400000 0 rs
Ethernet32 32,33,34,35,36,37,38,39 Ethernet32 5 400000 0 rs
Ethernet40 40,41,42,43,44,45,46,47 Ethernet40 6 400000 0 rs
Ethernet48 48,49,50,51,52,53,54,55 Ethernet48 7 400000 0 rs
Ethernet56 56,57,58,59,60,61,62,63 Ethernet56 8 400000 0 rs
Ethernet64 64,65,66,67,68,69,70,71 Ethernet64 9 400000 0 rs
Ethernet72 72,73,74,75,76,77,78,79 Ethernet72 10 400000 0 rs
Ethernet80 80,81,82,83,84,85,86,87 Ethernet80 11 400000 0 rs
Ethernet88 88,89,90,91,92,93,94,95 Ethernet88 12 400000 0 rs
Ethernet96 96,97,98,99,100,101,102,103 Ethernet96 13 400000 0 rs
Ethernet104 104,105,106,107,108,109,110,111 Ethernet104 14 400000 0 rs
Ethernet112 112,113,114,115,116,117,118,119 Ethernet112 15 400000 0 rs
Ethernet120 120,121,122,123,124,125,126,127 Ethernet120 16 400000 0 rs
Ethernet128 128,129,130,131,132,133,134,135 Ethernet128 17 400000 0 rs
Ethernet136 136,137,138,139,140,141,142,143 Ethernet136 18 400000 0 rs
Ethernet144 144,145,146,147,148,149,150,151 Ethernet144 19 400000 0 rs
Ethernet152 152,153,154,155,156,157,158,159 Ethernet152 20 400000 0 rs
Ethernet160 160,161,162,163,164,165,166,167 Ethernet160 21 400000 0 rs
Ethernet168 168,169,170,171,172,173,174,175 Ethernet168 22 400000 0 rs
Ethernet176 176,177,178,179,180,181,182,183 Ethernet176 23 400000 0 rs
Ethernet184 184,185,186,187,188,189,190,191 Ethernet184 24 400000 0 rs
Ethernet192 192,193,194,195,196,197,198,199 Ethernet192 25 400000 0 rs
Ethernet200 200,201,202,203,204,205,206,207 Ethernet200 26 400000 0 rs
Ethernet208 208,209,210,211,212,213,214,215 Ethernet208 27 400000 0 rs
Ethernet216 216,217,218,219,220,221,222,223 Ethernet216 28 400000 0 rs
Ethernet224 224,225,226,227,228,229,230,231 Ethernet224 29 400000 0 rs
Ethernet232 232,233,234,235,236,237,238,239 Ethernet232 30 400000 0 rs
Ethernet240 240,241,242,243,244,245,246,247 Ethernet240 31 400000 0 rs
Ethernet248 248,249,250,251,252,253,254,255 Ethernet248 32 400000 0 rs

View File

@ -0,0 +1,10 @@
{%- macro generate_tc_to_pg_map() %}
"TC_TO_PRIORITY_GROUP_MAP": {
"AZURE": {
"3": "3",
"4": "4"
}
},
{%- endmacro %}
{%- include 'qos_config.j2' %}

View File

@ -0,0 +1,3 @@
SAI_KEY_WARM_BOOT_WRITE_FILE=/var/warmboot/sai-warmboot.bin
SAI_KEY_WARM_BOOT_READ_FILE=/var/warmboot/sai-warmboot.bin

View File

@ -0,0 +1,40 @@
{
"instance": 0,
"chip_list": [
{
"id": "asic-0",
"chip_family": "Tofino2",
"instance": 0,
"pcie_sysfs_prefix": "/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0",
"pcie_domain": 0,
"pcie_bus": 5,
"pcie_fn": 0,
"pcie_dev": 0,
"pcie_int_mode": 1,
"sds_fw_path": "share/tofino_sds_fw/avago/firmware"
}
],
"p4_devices": [
{
"device-id": 0,
"agent0": "lib/platform/x86_64-accton_as9516bf_32d-r0/libpltfm_mgr.so",
"p4_programs": [
{
"p4_pipelines": [
{
"p4_pipeline_name": "pipe",
"config": "share/switch/pipe/tofino2.bin",
"context": "share/switch/pipe/context.json"
}
],
"program-name": "switch",
"switchsai": "lib/libswitchsai.so",
"bfrt-config": "share/switch/bf-rt.json",
"model_json_path" : "share/switch/aug_model.json",
"switchapi_port_add": false,
"non_default_port_ppgs": 5
}
]
}
]
}

View File

@ -0,0 +1 @@
../x86_64-accton_wedge100bf_32x-r0/plugins/

View File

@ -0,0 +1,6 @@
{
"skip_ledd": true,
"skip_xcvrd": false,
"skip_psud": false,
"skip_syseepromd": false
}

View File

@ -7,6 +7,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(BFN_MODULE) $(PYTHON_THRIFT)
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_MONTARA_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(BFN_NEWPORT_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WNC_OSW1800_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9180_32X_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9180_32X_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9280_64X_PLATFORM_MODULE) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(INGRASYS_S9280_64X_PLATFORM_MODULE)

View File

@ -0,0 +1,13 @@
# BFN Platform modules
BFN_NEWPORT_PLATFORM_MODULE_VERSION = 1.0
export BFN_NEWPORT_PLATFORM_MODULE_VERSION
BFN_NEWPORT_PLATFORM_MODULE = sonic-platform-modules-bfn-newport_$(BFN_NEWPORT_PLATFORM_MODULE_VERSION)_amd64.deb
$(BFN_NEWPORT_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-bfn-newport
$(BFN_NEWPORT_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
$(BFN_NEWPORT_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9516bf_32d-r0
SONIC_DPKG_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE)
SONIC_STRETCH_DEBS += $(BFN_NEWPORT_PLATFORM_MODULE)

View File

@ -1,6 +1,7 @@
include $(PLATFORM_PATH)/platform-modules-arista.mk include $(PLATFORM_PATH)/platform-modules-arista.mk
include $(PLATFORM_PATH)/platform-modules-bfn.mk include $(PLATFORM_PATH)/platform-modules-bfn.mk
include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk include $(PLATFORM_PATH)/platform-modules-bfn-montara.mk
include $(PLATFORM_PATH)/platform-modules-bfn-newport.mk
include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk include $(PLATFORM_PATH)/platform-modules-wnc-osw1800.mk
include $(PLATFORM_PATH)/platform-modules-ingrasys.mk include $(PLATFORM_PATH)/platform-modules-ingrasys.mk
include $(PLATFORM_PATH)/bfn-sai.mk include $(PLATFORM_PATH)/bfn-sai.mk

View File

@ -0,0 +1,15 @@
Copyright (C) 2016 Microsoft, Inc
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@ -0,0 +1,3 @@
# This file describes the maintainers for sonic-platform-modules-bfn-newport
# See the SONiC project governance document for more information
Mailinglist = sonicproject@googlegroups.com

View File

@ -0,0 +1,2 @@
# sonic-platform-modules-bfn-newport
Device drivers for support of BFN platform for the SONiC project

View File

@ -0,0 +1,5 @@
# BMC interface
auto usb0
allow-hotplug usb0
iface usb0 inet6
up ifconfig usb0 txqueuelen 64

View File

@ -0,0 +1,5 @@
sonic-platform-modules-bfn-newport (1.0) unstable; urgency=low
* Initial release
-- Support <support@barefootnetworks.com> Mon, 27 Sep 2019 18:00:00 -0800

View File

@ -0,0 +1,12 @@
Source: sonic-platform-modules-bfn-newport
Section: main
Priority: extra
Maintainer: Support <support@edge-core.com>
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
Package: sonic-platform-modules-bfn-newport
Architecture: amd64
Depends: linux-image-4.9.0-9-2-amd64
Description: kernel module for bfn platform fpga and scripts for the devices such as fan, led, sfp

View File

@ -0,0 +1,15 @@
Provides linux kernel driver for BF PCIe devices
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@ -0,0 +1,35 @@
#!/usr/bin/make -f
export INSTALL_MOD_DIR:=extra
PACKAGE_NAME := sonic-platform-modules-bfn-newport
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MODULE_SRC := $(shell pwd)/modules
SCRIPT_SRC := $(shell pwd)/scripts
CONFIGS_SRC := $(shell pwd)/configs
%:
dh $@
override_dh_auto_build:
make -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
override_dh_auto_install:
dh_installdirs -p$(PACKAGE_NAME) $(KERNEL_SRC)/$(INSTALL_MOD_DIR)
cp $(MODULE_SRC)/*.ko debian/$(PACKAGE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR)
dh_installdirs -p$(PACKAGE_NAME) usr/local/bin
cp -r $(SCRIPT_SRC)/* debian/$(PACKAGE_NAME)/usr/local/bin
dh_installdirs -p$(PACKAGE_NAME) etc/network/interfaces.d/
cp -r $(CONFIGS_SRC)/network/interfaces.d/* debian/$(PACKAGE_NAME)/etc/network/interfaces.d/
override_dh_usrlocal:
override_dh_pysupport:
override_dh_clean:
dh_clean
rm -f $(MODULE_SRC)/*.o $(MODULE_SRC)/*.ko $(MODULE_SRC)/*.mod.c $(MODULE_SRC)/.*.cmd
rm -f $(MODULE_SRC)/Module.markers $(MODULE_SRC)/Module.symvers $(MODULE_SRC)/modules.order
rm -rf $(MODULE_SRC)/.tmp_versions

View File

@ -0,0 +1,2 @@
obj-m := bf_fpga.o
bf_fpga-y := bf_fpga_main.o bf_fpga_ioctl.o bf_fpga_sysfs.o i2c/bf_fpga_i2c.o i2c/bf_fpga_i2c_ctrl.o i2c/bf_fpga_i2c_porting.o

View File

@ -0,0 +1,196 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#include <linux/types.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include "bf_fpga_priv.h"
#include "bf_fpga_ioctl.h"
#include "i2c/bf_fpga_i2c.h"
int bf_fpga_ioctl(struct bf_pci_dev *bfdev,
unsigned int cmd,
unsigned long arg) {
void *addr = (void __user *)arg;
int ret = -1;
if (!bfdev || !addr) {
return -EFAULT;
}
switch (cmd) {
case BF_FPGA_IOCTL_I2C_CTL: {
bf_fpga_i2c_ctl_t i2c_ctl;
bool busy;
if (copy_from_user(&i2c_ctl, addr, sizeof(bf_fpga_i2c_ctl_t))) {
return -EFAULT;
}
switch (i2c_ctl.control_type) {
case BF_FPGA_I2C_START:
ret = fpga_i2c_start(i2c_ctl.inst_hndl.bus_id);
break;
case BF_FPGA_I2C_STOP:
ret = fpga_i2c_stop(i2c_ctl.inst_hndl.bus_id);
break;
case BF_FPGA_I2C_RESET:
ret = fpga_i2c_reset(i2c_ctl.inst_hndl.bus_id);
break;
case BF_FPGA_I2C_BUSY:
ret = fpga_i2c_is_busy(i2c_ctl.inst_hndl.bus_id, &busy);
if (ret == 0) {
if (copy_to_user(&(((bf_fpga_i2c_ctl_t *)addr)->is_busy),
&busy,
sizeof(busy))) {
return -EFAULT;
}
}
break;
case BF_FPGA_I2C_INST_EN:
ret = fpga_i2c_inst_en(
i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, true);
break;
case BF_FPGA_I2C_INST_DIS:
ret = fpga_i2c_inst_en(
i2c_ctl.inst_hndl.bus_id, i2c_ctl.inst_hndl.inst_id, false);
break;
case BF_FPGA_I2C_INST_PMT:
break;
case BF_FPGA_I2C_INST_STOP_ON_ERR:
break;
case BF_FPGA_I2C_INST_INT_EN:
break;
default:
break;
}
break;
}
case BF_FPGA_IOCTL_I2C_SET_CLK: {
bf_fpga_i2c_set_clk_t i2c_clk;
if (copy_from_user(&i2c_clk, addr, sizeof(bf_fpga_i2c_set_clk_t))) {
return -EFAULT;
}
ret = fpga_i2c_set_clk(i2c_clk.bus_id, i2c_clk.clock_div);
break;
}
case BF_FPGA_IOCTL_I2C_ONETIME: {
bf_fpga_i2c_t i2c_op;
int i;
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
return -EFAULT;
}
ret = fpga_i2c_oneshot(&i2c_op);
if (ret == 0) {
/* copy read data to user area */
for (i = 0; i < i2c_op.num_i2c; i++) {
if (i2c_op.i2c_inst[i].rd_cnt) {
if (copy_to_user(&(((bf_fpga_i2c_t *)addr)->i2c_inst[i].rd_buf),
&i2c_op.i2c_inst[i].rd_buf,
i2c_op.i2c_inst[i].rd_cnt)) {
return -EFAULT;
}
}
}
} else {
printk(KERN_ERR
"fpga i2c ioctl oneshot bus %d error %d i2c_addr 0x%hhx:0x%hhx "
"i2c_status 0x%hhx:0x%hhx\n",
i2c_op.inst_hndl.bus_id,
ret,
i2c_op.i2c_inst[0].i2c_addr,
i2c_op.i2c_inst[1].i2c_addr,
i2c_op.i2c_inst[0].status,
i2c_op.i2c_inst[1].status);
}
break;
}
case BF_FPGA_IOCTL_I2C_ADD_PR: {
bf_fpga_i2c_t i2c_op;
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
return -EFAULT;
}
ret = fpga_i2c_pr_add(&i2c_op);
if (ret == 0) {
/* copy read data to user area */
if (copy_to_user(&((bf_fpga_i2c_t *)addr)->inst_hndl.inst_id,
&i2c_op.inst_hndl.inst_id,
sizeof(i2c_op.inst_hndl.inst_id))) {
return -EFAULT;
}
} else {
printk(KERN_ERR "fpga i2c ioctl add-pr error %d on bus %d\n",
ret,
i2c_op.inst_hndl.bus_id);
}
break;
}
case BF_FPGA_IOCTL_I2C_DEL_PR: {
bf_fpga_i2c_t i2c_op;
if (copy_from_user(&i2c_op, addr, sizeof(bf_fpga_i2c_t))) {
return -EFAULT;
}
ret = fpga_i2c_del(&i2c_op);
if (ret != 0) {
printk(KERN_ERR "fpga i2c ioctl del-pr error %d on bus %d\n",
ret,
i2c_op.inst_hndl.bus_id);
}
break;
}
case BF_FPGA_IOCTL_I2C_RD_DATA: {
bf_fpga_i2c_rd_data_t i2c_rd_data;
/* get user supplied offset and rd_cnt */
if (copy_from_user(
&i2c_rd_data, addr, offsetof(bf_fpga_i2c_rd_data_t, rd_buf))) {
return -EFAULT;
}
ret = fpga_i2c_data_read(i2c_rd_data.inst_hndl.bus_id,
i2c_rd_data.inst_hndl.inst_id,
i2c_rd_data.offset,
i2c_rd_data.rd_cnt,
i2c_rd_data.rd_buf);
if (ret == 0) {
if (copy_to_user(&(((bf_fpga_i2c_rd_data_t *)addr)->rd_buf),
&i2c_rd_data.rd_buf,
i2c_rd_data.rd_cnt)) {
return -EFAULT;
}
} else {
printk(KERN_ERR "fpga i2c ioctl rd-data error %d on bus %d inst %d\n",
ret,
i2c_rd_data.inst_hndl.bus_id,
i2c_rd_data.inst_hndl.inst_id);
}
break;
}
default:
return -EINVAL;
}
return ret;
}

View File

@ -0,0 +1,131 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_IOCTL_H_
#define _BF_FPGA_IOCTL_H_
#ifdef __KERNEL__
#include <linux/ioctl.h>
#else
#include <sys/ioctl.h>
#endif /* __KERNEL__ */
#define BF_FPGA_IOC_MAGIC 'f'
#define BF_I2C_FPGA_NUM_CTRL 34
#define BF_FPGA_MAX_I2C_RD_DATA 128
#define BF_FPGA_MAX_I2C_WR_DATA 129
/* i2c control types */
#define BF_FPGA_I2C_START 1
#define BF_FPGA_I2C_STOP 2
#define BF_FPGA_I2C_BUSY 3
#define BF_FPGA_I2C_INST_EN 4
#define BF_FPGA_I2C_INST_DIS 5
#define BF_FPGA_I2C_INST_PMT 6
#define BF_FPGA_I2C_INST_STOP_ON_ERR 7
#define BF_FPGA_I2C_INST_INT_EN 8
#define BF_FPGA_I2C_RESET 9
/* i2c operation types */
#define BF_FPGA_I2C_NOP 0
#define BF_FPGA_I2C_WRITE \
1 /* <i2c-addr-wr> / <wr-d0> <wr-d1>..[max 129 bytes] */
#define BF_FPGA_I2C_READ \
2 /* <i2c-addr-rd> / <rd-d0> <rd-d1>..[max 128 bytes] */
#define BF_FPGA_I2C_ADDR_READ \
3 /* <i2c-addr-wr> / <upto 4 bytes of register offset / <R/S> / \
<i2c-addr-rd> <upto 4 bytes of read data> */
#define FPGA_I2c_ONESHOT_BEGIN_INDEX 0
#define FPGA_I2C_ONESHOT_NUM_INST 15
#define FPGA_I2C_PERIODIC_BEGIN_INDEX (FPGA_I2C_ONESHOT_NUM_INST)
#define FPGA_I2C_PERIODIC_NUM_INST 16
#define FPGA_I2C_NUM_INST \
(FPGA_I2C_ONESHOT_NUM_INST + FPGA_I2C_PERIODIC_NUM_INST)
/* maximum i2c instructions that can be handled in one system call */
#define BF_FPGA_I2C_MAX_NUM_INST 3
typedef struct bf_fpga_i2c_set_clk_s {
/* 0:100k, 1:400k, 2:1M, or: 125e6/<desired freq>/3 */
int clock_div; /* clock divider */
unsigned char bus_id; /* controller index */
} bf_fpga_i2c_set_clk_t;
typedef struct bf_fpga_inst_hndl_s {
int inst_id; /* instruction index within the controller memory space */
unsigned char bus_id; /* controller index */
unsigned char status;
} bf_fpga_inst_hndl_t;
typedef struct bf_fpga_i2c_inst_s {
bool preemt;
bool en;
unsigned char i2c_addr; /* i2c device address in 7 bit format */
unsigned char i2c_type; /* type of i2c cycle */
unsigned char delay; /* delay in TBD - microseconds before i2c transaction */
unsigned char ctrl;
unsigned char wr_cnt; /* number of bytes to write (after i2c address) */
unsigned char rd_cnt; /* number of bytes to read */
union {
unsigned char
wr_buf[BF_FPGA_MAX_I2C_WR_DATA]; /* write data source buffer */
unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA]; /* read data dest buffer */
};
unsigned char status;
unsigned char retry_cnt; /* if fpga maintains retry count */
unsigned char mux; /* if fpga maintains internal MUX */
} bf_fpga_i2c_inst_t;
typedef struct bf_fpga_i2c_s {
unsigned char num_i2c; /* number of i2c operations */
unsigned char one_time; /* one time or periodic */
bf_fpga_inst_hndl_t inst_hndl;
bf_fpga_i2c_inst_t i2c_inst[BF_FPGA_I2C_MAX_NUM_INST];
} bf_fpga_i2c_t;
typedef struct bf_fpga_i2c_rd_data_s {
bf_fpga_inst_hndl_t inst_hndl;
unsigned char offset;
unsigned char rd_cnt;
unsigned char rd_buf[BF_FPGA_MAX_I2C_RD_DATA];
} bf_fpga_i2c_rd_data_t;
typedef struct bf_fpga_i2c_ctl_s {
bf_fpga_inst_hndl_t inst_hndl;
unsigned char control_type; /* start, stop, reset, enable, disable or busy */
bool is_busy;
} bf_fpga_i2c_ctl_t;
#define BF_FPGA_IOCTL_I2C_CTL _IOWR(BF_FPGA_IOC_MAGIC, 0, bf_fpga_i2c_ctl_t)
#define BF_FPGA_IOCTL_I2C_ONETIME _IOWR(BF_FPGA_IOC_MAGIC, 1, bf_fpga_i2c_t)
#define BF_FPGA_IOCTL_I2C_ADD_PR _IOWR(BF_FPGA_IOC_MAGIC, 2, bf_fpga_i2c_t)
#define BF_FPGA_IOCTL_I2C_DEL_PR _IOWR(BF_FPGA_IOC_MAGIC, 3, bf_fpga_i2c_t)
#define BF_FPGA_IOCTL_I2C_RD_DATA \
_IOWR(BF_FPGA_IOC_MAGIC, 4, bf_fpga_i2c_rd_data_t)
#define BF_FPGA_IOCTL_I2C_SET_CLK \
_IOW(BF_FPGA_IOC_MAGIC, 5, bf_fpga_i2c_set_clk_t)
#endif /* _BF_FPGA_IOCTL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_H_
#define _BF_FPGA_H_
#define PCI_VENDOR_ID_BF 0x1d1c
#define BF_FPGA_DEV_ID_JBAY_0 0x01F0
#ifndef PCI_MSIX_ENTRY_SIZE
#define PCI_MSIX_ENTRY_SIZE 16
#define PCI_MSIX_ENTRY_LOWER_ADDR 0
#define PCI_MSIX_ENTRY_UPPER_ADDR 4
#define PCI_MSIX_ENTRY_DATA 8
#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
#endif
#define BF_CLASS_NAME "bf_fpga"
#define BF_FPGA_MAX_DEVICE_CNT 1
#define BF_INTR_MODE_NONE_NAME "none"
#define BF_INTR_MODE_LEGACY_NAME "legacy"
#define BF_INTR_MODE_MSI_NAME "msi"
#define BF_INTR_MODE_MSIX_NAME "msix"
#define BF_MAX_BAR_MAPS 6
#define BF_MSIX_ENTRY_CNT 1
#define BF_MSI_ENTRY_CNT 1
/* sysfs codes */
#define BF_SYSFS_NEW_DEVICE 1
#define BF_SYSFS_RM_DEVICE 0
#define BF_SYSFS_I2C_START 2
/* interrupt mode */
enum bf_intr_mode {
BF_INTR_MODE_NONE = 0,
BF_INTR_MODE_LEGACY,
BF_INTR_MODE_MSI,
BF_INTR_MODE_MSIX
};
/* device memory */
struct bf_dev_mem {
const char *name;
phys_addr_t addr;
resource_size_t size;
void __iomem *internal_addr;
};
struct bf_listener {
struct bf_pci_dev *bfdev;
s32 event_count[BF_MSIX_ENTRY_CNT];
int minor;
struct bf_listener *next;
};
/* device information */
struct bf_dev_info {
struct module *owner;
struct device *dev;
int minor;
atomic_t event[BF_MSIX_ENTRY_CNT];
wait_queue_head_t wait;
const char *version;
struct bf_dev_mem mem[BF_MAX_BAR_MAPS];
struct msix_entry *msix_entries;
long irq; /* first irq vector */
int num_irq; /* number of irq vectors */
unsigned long irq_flags; /* sharable ?? */
int pci_error_state; /* was there a pci bus error */
};
/* cookie to be passed to IRQ handler, useful especially with MSIX */
struct bf_int_vector {
struct bf_pci_dev *bf_dev;
int int_vec_offset;
};
/* sysfs related structs */
#define BF_FPGA_SYSFS_CNT 64
#define BF_FPGA_SYSFS_NAME_SIZE 32
struct bf_fpga_sysfs_buff {
struct device_attribute dev_attr;
char name[BF_FPGA_SYSFS_NAME_SIZE];
int bus_id;
unsigned char i2c_addr;
size_t i2c_rd_size; /* bytes to read from the device */
int sysfs_code; /* unique code for each sysfs file */
struct bf_pci_dev *fpgadev; /* back pointer */
bool in_use;
};
/**
* structure describing the private information for a BF pcie device.
*/
struct bf_pci_dev {
struct bf_dev_info info;
struct pci_dev *pdev;
enum bf_intr_mode mode;
u8 instance;
char name[16];
struct bf_int_vector bf_int_vec[BF_MSIX_ENTRY_CNT];
struct bf_listener *
listener_head; /* head of a singly linked list of listeners */
struct bf_fpga_sysfs_buff fpga_sysfs_buff[BF_FPGA_SYSFS_CNT];
struct bf_fpga_sysfs_buff fpga_sysfs_new_device;
struct bf_fpga_sysfs_buff fpga_sysfs_rm_device;
struct bf_fpga_sysfs_buff fpga_sysfs_st_i2c;
spinlock_t sysfs_slock;
};
int bf_fpga_ioctl(struct bf_pci_dev *bfdev,
unsigned int cmd,
unsigned long arg);
int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev);
void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev);
#endif /* _BF_FPGA_H_ */

View File

@ -0,0 +1,335 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/cdev.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include "bf_fpga_priv.h"
#include "bf_fpga_ioctl.h"
#include "i2c/bf_fpga_i2c.h"
/* reads 1 byte from the i2c device */
static ssize_t bf_fpga_sysfs_i2c_get(struct device *dev,
struct device_attribute *attr,
char *buf) {
bf_fpga_i2c_t i2c_op;
ssize_t size, cur_size;
struct bf_fpga_sysfs_buff *sysfs_buf =
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
if (!sysfs_buf) {
printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_read\n");
return -ENXIO; /* something not quite right here; but, don't panic */
}
i2c_op.num_i2c = 1;
i2c_op.one_time = 1;
i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id;
i2c_op.i2c_inst[0].preemt = false;
i2c_op.i2c_inst[0].en = true;
i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr;
i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_READ;
i2c_op.i2c_inst[0].delay = 0;
i2c_op.i2c_inst[0].wr_cnt = 0;
cur_size = sysfs_buf->i2c_rd_size;
/* limit to PAGE_SIZE per the sysfs contract */
if (cur_size >= PAGE_SIZE) {
cur_size = PAGE_SIZE;
}
size = 0;
while (cur_size > 0) {
unsigned char cur_cnt;
if (cur_size > 64) {
cur_cnt = 64;
} else {
cur_cnt = (unsigned char)cur_size;
}
i2c_op.i2c_inst[0].rd_cnt = cur_cnt;
if (fpga_i2c_oneshot(&i2c_op)) {
printk(KERN_ERR
"fpga-i2c read one-shot error bus %d addr 0x%hhx status 0x%hhx\n",
i2c_op.inst_hndl.bus_id,
i2c_op.i2c_inst[0].i2c_addr,
i2c_op.i2c_inst[0].status);
return -EIO;
}
memcpy(buf, i2c_op.i2c_inst[0].rd_buf, cur_cnt);
buf += cur_cnt;
size += cur_cnt;
cur_size -= cur_cnt;
}
return size;
}
/* write the number of bytes supplied to the i2c device, 1st byte has to be
the count(max 8) */
static ssize_t bf_fpga_sysfs_i2c_set(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
bf_fpga_i2c_t i2c_op;
size_t size, cur_cnt;
struct bf_fpga_sysfs_buff *sysfs_buf =
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
if (!sysfs_buf || (count == 0)) {
printk(KERN_ERR "fpga-i2c bad attr pointer in sysfs_write\n");
return -ENXIO; /* something not quite right here; but, don't panic */
}
size = 0;
while (count > 0) {
if (count > 64) {
cur_cnt = 64;
} else {
cur_cnt = count;
}
i2c_op.i2c_inst[0].wr_cnt = cur_cnt;
i2c_op.i2c_inst[0].rd_cnt = 0;
memcpy(i2c_op.i2c_inst[0].wr_buf, buf, cur_cnt);
i2c_op.num_i2c = 1;
i2c_op.one_time = 1;
i2c_op.inst_hndl.bus_id = sysfs_buf->bus_id;
i2c_op.i2c_inst[0].preemt = false;
i2c_op.i2c_inst[0].en = true;
i2c_op.i2c_inst[0].i2c_addr = sysfs_buf->i2c_addr;
i2c_op.i2c_inst[0].i2c_type = BF_FPGA_I2C_WRITE;
i2c_op.i2c_inst[0].delay = 0;
if (fpga_i2c_oneshot(&i2c_op)) {
printk(
KERN_ERR
"fpga-i2c write one-shot error bus %d addr 0x%hhx status 0x%hhx\n",
i2c_op.inst_hndl.bus_id,
i2c_op.i2c_inst[0].i2c_addr,
i2c_op.i2c_inst[0].status);
return -EIO;
}
buf += cur_cnt;
size += cur_cnt;
count -= cur_cnt;
}
return size;
}
static int find_matching_sysfs_buf(struct bf_pci_dev *fpgadev,
int bus_id,
unsigned char i2c_addr) {
int i;
/* check if a sysfs entry already exists */
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
if (fpgadev->fpga_sysfs_buff[i].bus_id == bus_id &&
fpgadev->fpga_sysfs_buff[i].i2c_addr == i2c_addr) {
return i;
}
}
/* could not find a matching sysfs buffer */
return -1;
}
static ssize_t bf_fpga_sysfs_fixed_get(struct device *dev,
struct device_attribute *attr,
char *buf) {
(void)dev;
(void)attr;
(void)buf;
return -ENOSYS;
}
static ssize_t bf_fpga_sysfs_fixed_set(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
struct bf_pci_dev *fpgadev;
int i, en, bus_id, ret, rd_size;
char fname[BF_FPGA_SYSFS_NAME_SIZE];
unsigned char i2c_addr;
struct bf_fpga_sysfs_buff *new_buf;
struct bf_fpga_sysfs_buff *sysfs_buf =
container_of(attr, struct bf_fpga_sysfs_buff, dev_attr);
if (!sysfs_buf || (count == 0)) {
printk(KERN_ERR "fpga i2c bad attr pointer in fixed_sysfs_write\n");
return -ENXIO; /* something not quite right here; but, don't panic */
}
fpgadev = sysfs_buf->fpgadev;
switch (sysfs_buf->sysfs_code) {
case BF_SYSFS_NEW_DEVICE: /* new_device request */
ret = sscanf(buf, "%s %d %hhx %d", fname, &bus_id, &i2c_addr, &rd_size);
/* default rd_size to 1 if not supplied or invalid */
if (ret < 3) {
return -EINVAL;
}
if (ret < 4 || rd_size > PAGE_SIZE) {
rd_size = 1;
}
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) {
return -EINVAL;
}
/* find out the free sysfs_buffer to use */
spin_lock(&fpgadev->sysfs_slock);
if (find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr) != -1) {
/* there is already an matching entry */
spin_unlock(&fpgadev->sysfs_slock);
return -ENOSPC;
}
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
if (!fpgadev->fpga_sysfs_buff[i].in_use) {
fpgadev->fpga_sysfs_buff[i].in_use = true;
new_buf = &fpgadev->fpga_sysfs_buff[i];
new_buf->i2c_addr = i2c_addr;
new_buf->i2c_rd_size = (size_t)rd_size;
new_buf->bus_id = bus_id;
break;
}
}
spin_unlock(&fpgadev->sysfs_slock);
if (i >= BF_FPGA_SYSFS_CNT) {
/* no free buffer available, return with ERROR */
return -ENOSPC;
}
/* create a new sysfs entry now */
new_buf->dev_attr.show = bf_fpga_sysfs_i2c_get;
new_buf->dev_attr.store = bf_fpga_sysfs_i2c_set;
new_buf->fpgadev = fpgadev;
new_buf->dev_attr.attr.mode = S_IWUSR | S_IRUGO;
new_buf->sysfs_code = 0;
snprintf(new_buf->name, BF_FPGA_SYSFS_NAME_SIZE, "%s", fname);
new_buf->dev_attr.attr.name = new_buf->name;
ret = device_create_file(&(fpgadev->pdev->dev), &new_buf->dev_attr);
break;
case BF_SYSFS_RM_DEVICE: /* remove device request */
ret = sscanf(buf, "%d %hhx", &bus_id, &i2c_addr);
if (ret < 2) {
return -EINVAL;
}
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || i2c_addr >= 0x80) {
return -EINVAL;
}
/* delete the sysfs file corresponding to the i2c address */
spin_lock(&fpgadev->sysfs_slock);
i = find_matching_sysfs_buf(fpgadev, bus_id, i2c_addr);
if (i == -1) {
/* there is no matching entry */
spin_unlock(&fpgadev->sysfs_slock);
return -EINVAL;
}
/* must invalidate bus_id and i2c_addr when marking the buffer
* not-in-use
*/
new_buf = &fpgadev->fpga_sysfs_buff[i];
new_buf->i2c_addr = 0xff;
new_buf->bus_id = -1;
fpgadev->fpga_sysfs_buff[i].in_use = false;
spin_unlock(&fpgadev->sysfs_slock);
device_remove_file(&fpgadev->pdev->dev, &new_buf->dev_attr);
new_buf->name[0] = 0; /* nullify the name */
ret = 0;
break;
case BF_SYSFS_I2C_START: /* start-stop i2c request */
ret = sscanf(buf, "%d %d", &bus_id, &en);
if (ret < 2) {
return -EINVAL;
}
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
return -EINVAL;
}
if (en) {
ret = fpga_i2c_start(bus_id);
} else {
ret = fpga_i2c_stop(bus_id);
}
break;
default:
ret = -EINVAL;
}
return ((ret == 0) ? count : ret);
}
int bf_fpga_sysfs_add(struct bf_pci_dev *fpgadev) {
int rc = 0;
u8 *name;
spin_lock_init(&fpgadev->sysfs_slock);
/* Add two sysfs files statically, new_device and remove_device.
* Handlers of these two fles can dynamically add more sysfs
* files (or remove files) based on the platform.
*/
fpgadev->fpga_sysfs_new_device.dev_attr.show = bf_fpga_sysfs_fixed_get;
fpgadev->fpga_sysfs_new_device.dev_attr.store = bf_fpga_sysfs_fixed_set;
fpgadev->fpga_sysfs_new_device.fpgadev = fpgadev;
fpgadev->fpga_sysfs_new_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
fpgadev->fpga_sysfs_new_device.sysfs_code = BF_SYSFS_NEW_DEVICE;
name = fpgadev->fpga_sysfs_new_device.name;
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "new_device");
fpgadev->fpga_sysfs_new_device.dev_attr.attr.name = name;
rc |= device_create_file(&(fpgadev->pdev->dev),
&fpgadev->fpga_sysfs_new_device.dev_attr);
fpgadev->fpga_sysfs_rm_device.dev_attr.show = bf_fpga_sysfs_fixed_get;
fpgadev->fpga_sysfs_rm_device.dev_attr.store = bf_fpga_sysfs_fixed_set;
fpgadev->fpga_sysfs_rm_device.fpgadev = fpgadev;
fpgadev->fpga_sysfs_rm_device.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
fpgadev->fpga_sysfs_rm_device.sysfs_code = BF_SYSFS_RM_DEVICE;
name = fpgadev->fpga_sysfs_rm_device.name;
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "remove_device");
fpgadev->fpga_sysfs_rm_device.dev_attr.attr.name = name;
rc |= device_create_file(&(fpgadev->pdev->dev),
&fpgadev->fpga_sysfs_rm_device.dev_attr);
/* sysfs for i2c start-stop control */
fpgadev->fpga_sysfs_st_i2c.dev_attr.show = bf_fpga_sysfs_fixed_get;
fpgadev->fpga_sysfs_st_i2c.dev_attr.store = bf_fpga_sysfs_fixed_set;
fpgadev->fpga_sysfs_st_i2c.fpgadev = fpgadev;
fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
fpgadev->fpga_sysfs_st_i2c.sysfs_code = BF_SYSFS_I2C_START;
name = fpgadev->fpga_sysfs_st_i2c.name;
snprintf(name, BF_FPGA_SYSFS_NAME_SIZE, "i2c_start");
fpgadev->fpga_sysfs_st_i2c.dev_attr.attr.name = name;
rc |= device_create_file(&(fpgadev->pdev->dev),
&fpgadev->fpga_sysfs_st_i2c.dev_attr);
return rc;
}
void bf_fpga_sysfs_del(struct bf_pci_dev *fpgadev) {
int i;
device_remove_file(&fpgadev->pdev->dev,
&fpgadev->fpga_sysfs_new_device.dev_attr);
device_remove_file(&fpgadev->pdev->dev,
&fpgadev->fpga_sysfs_rm_device.dev_attr);
device_remove_file(&fpgadev->pdev->dev, &fpgadev->fpga_sysfs_st_i2c.dev_attr);
for (i = 0; i < BF_FPGA_SYSFS_CNT; i++) {
if (fpgadev->fpga_sysfs_buff[i].in_use) {
device_remove_file(&fpgadev->pdev->dev,
&fpgadev->fpga_sysfs_buff[i].dev_attr);
}
}
}

View File

@ -0,0 +1,516 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#include <linux/types.h>
#include "bf_fpga_i2c_priv_porting.h"
#include <bf_fpga_ioctl.h>
#include "bf_fpga_i2c_priv.h"
#include "bf_fpga_i2c.h"
#include "bf_fpga_i2c_reg.h"
/* allocate find physically contiguous free blocks of instructions in one time
* or periodic area and mark them "in-use" */
static int get_next_free_index(fpga_i2c_controller_t *i2c_ctrl,
int cnt,
bool pr) {
int i, j, begin, end;
if (pr) {
begin = FPGA_I2C_PERIODIC_BEGIN_INDEX;
end = FPGA_I2C_NUM_INST;
} else {
begin = FPGA_I2c_ONESHOT_BEGIN_INDEX;
end = FPGA_I2C_ONESHOT_NUM_INST;
}
bf_fpga_fast_lock(&i2c_ctrl->spinlock);
for (i = begin; i < end;) {
/* check if there are cnt number of free slots here */
for (j = 0; j < cnt; j++) {
if (i2c_ctrl->i2c_inst[i + j].in_use) {
break;
}
}
if (j == cnt) {
/* we found enough free slots, so, return i */
break;
} else {
/* we did not find enough free slots, continue searching */
i += (j + 1);
continue;
}
}
if (i < end) {
for (j = 0; j < cnt; j++) {
i2c_ctrl->i2c_inst[i + j].in_use = true;
}
} else {
i = -1;
}
bf_fpga_fast_unlock(&i2c_ctrl->spinlock);
return i;
}
/* free physically contiguous in-use blocks of instructions */
static void release_index(fpga_i2c_controller_t *i2c_ctrl,
int inst_id,
int cnt) {
int i;
if (inst_id < 0 || (inst_id + cnt) >= FPGA_I2C_NUM_INST) {
return; /* invalid id */
}
bf_fpga_fast_lock(&i2c_ctrl->spinlock);
for (i = inst_id; i < (inst_id + cnt); i++) {
i2c_ctrl->i2c_inst[i].in_use = false;
}
bf_fpga_fast_unlock(&i2c_ctrl->spinlock);
}
/* convert miroseconds to i2c-instruction delay parameter */
static int us_to_fpga_delay(int microsec) {
int delay;
if (microsec < 10) {
delay = 0;
} else if (microsec < 100) {
delay = 1;
} else if (microsec < 1000) {
delay = 2;
} else if (microsec < 10000) {
delay = 3;
} else if (microsec < 100000) {
delay = 4;
} else if (microsec < 1000000) {
delay = 5;
} else {
delay = 6;
}
return delay;
}
/* populate single i2c_instruction at the given instruction slot */
static int fpga_i2c_enqueue(int bus_id,
int inst_id,
bf_fpga_i2c_inst_t *i2c_inst) {
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
int delay = us_to_fpga_delay(i2c_inst->delay);
uint32_t wd0 = 0, wd1 = 0;
uint32_t i2c_data[2];
uint8_t i2c_addr, num_wr, num_rd;
i2c_addr = i2c_inst->i2c_addr;
num_wr = i2c_inst->wr_cnt;
num_rd = i2c_inst->rd_cnt;
if (i2c_addr > 0x7F || num_wr > 129 || num_rd > 128) {
return BF_FPGA_EINVAL;
}
if (i2c_inst->preemt) {
wd0 |= I2C_INST_PMT;
}
if (i2c_inst->en) {
wd0 |= I2C_INST_EN;
}
i2c_data[0] = i2c_data[1] = 0; /* clear on init */
switch (i2c_inst->i2c_type) {
case BF_FPGA_I2C_NOP:
/* add delay + enable */
wd0 |= (I2C_NOP | (delay << I2C_DELAY_SHF));
break;
case BF_FPGA_I2C_WRITE:
if (num_wr == 0) {
return BF_FPGA_EINVAL;
}
wd0 |= (I2C_WR_ADDR_DATA | (delay << I2C_DELAY_SHF));
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
/* copy the first byte into register address */
wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET);
wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF);
if (num_wr <= 9) {
/* copy data into instruction area */
memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1));
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]);
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]);
} else {
/* copy the data in data area */
int len = num_wr - 1;
uint32_t addr;
uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]);
/* store the data pointer Note the indexing required by FPGA specs */
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
addr = i2c_data[0];
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
/* do byte write to avoid endianness mismatch */
while (len--) {
bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val);
addr++;
val++;
}
}
break;
case BF_FPGA_I2C_READ:
if (num_rd == 0) {
return BF_FPGA_EINVAL;
}
wd0 |= (I2C_RD_DATA | (delay << I2C_DELAY_SHF));
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
wd1 |= ((num_rd) << I2C_RD_CNT_SHF);
if (num_rd > 8) {
/* store the data area pointer */
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
}
break;
case BF_FPGA_I2C_ADDR_READ:
if (num_wr == 0 || num_rd == 0) {
return BF_FPGA_EINVAL;
}
wd0 |= (I2C_RD_ADDR_DATA_BURST | (delay << I2C_DELAY_SHF));
wd1 |= (i2c_inst->i2c_addr << I2C_DEV_ADDR_SHF);
/* 1st byte of the write buf goes into "register address" field */
wd1 |= ((num_wr - 1) << I2C_WR_CNT_SHF);
wd1 |= ((i2c_inst->wr_buf[0]) << I2C_CMD_OFFSET);
wd1 |= ((num_rd) << I2C_RD_CNT_SHF);
/* less than 8 bytes data goes to the instruction area */
if ((num_wr - 1 + num_rd) <= 8) {
memcpy(i2c_data, &i2c_inst->wr_buf[1], (num_wr - 1));
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0]);
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_HI(inst_id), i2c_data[1]);
} else {
int len = num_wr - 1;
uint32_t addr;
uint8_t *val = (uint8_t *)(&i2c_inst->wr_buf[1]);
/* store the data area pointer */
i2c_data[0] = BF_FPGA_I2C_DATA_AREA(inst_id);
addr = i2c_data[0];
bf_fpga_i2c_reg_write32(
i2c_ctrl, Bf_FPGA_I2C_INST_DATA_LO(inst_id), i2c_data[0] / 4);
/* copy the data in data area */
while (len--) {
bf_fpga_i2c_reg_write8(i2c_ctrl, addr, *val);
addr++;
val++;
}
}
break;
default:
return BF_FPGA_EINVAL;
}
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id), wd1);
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), wd0);
return BF_FPGA_OK;
}
/* get the i2c completion status of a particular instruction */
static uint32_t fpga_i2c_get_status(int bus_id, int inst_id) {
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
uint32_t addr = Bf_FPGA_I2C_INST_CTRL(inst_id);
return (bf_fpga_i2c_reg_read32(i2c_ctrl, addr) & I2C_STATUS_MASK);
}
/** FPGA I2C data read (assumes locked by caller and no need to stop i2c)
*
* read the data following a read type i2c operation
*
* @param bus_id
* i2c controller id
* @param inst_id
* instruction id within this controller space
* @param offset
* offset in the data-area where read-data is available
* @param num_rd
* number of bytes to read
* @param rd_buf
* buffer to read into
* @return
* 0 on success and <0 on error
*/
static int fpga_i2c_data_read_locked(fpga_i2c_controller_t *i2c_ctrl,
int inst_id,
uint8_t offset,
uint8_t num_rd,
uint8_t *rd_buf) {
uint8_t i;
uint32_t addr, data_cnt;
if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 ||
inst_id >= FPGA_I2C_NUM_INST) {
return BF_FPGA_EINVAL;
}
/* find out the wr_cnt + rd_cnt from the already executed instruction field */
data_cnt = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_PARAM(inst_id));
/* point to data area if the (wr_cnt + rd_cnt) > 8 */
data_cnt &= 0xffff; /* retain only the length fields */
if (((data_cnt & 0xff) + (data_cnt >> 8)) <= 8) {
addr = Bf_FPGA_I2C_INST_DATA_LO(inst_id) + offset;
} else {
addr = BF_FPGA_I2C_DATA_AREA(inst_id) + offset;
}
for (i = 0; i < num_rd; i++) {
*rd_buf = bf_fpga_i2c_reg_read8(i2c_ctrl, addr);
addr++;
rd_buf++;
}
return BF_FPGA_OK;
}
/** FPGA I2C data read
*
* read the data following a read type i2c operation
*
* @param bus_id
* i2c controller id
* @param inst_id
* instruction id within this controller space
* @param offset
* offset in the data-area where read-data is available
* @param num_rd
* number of bytes to read
* @param rd_buf
* buffer to read into
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_data_read(
int bus_id, int inst_id, uint8_t offset, uint8_t num_rd, uint8_t *rd_buf) {
fpga_i2c_controller_t *i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
int ret;
bool i2c_running;
uint8_t val;
if (!i2c_ctrl || !rd_buf || !num_rd || inst_id < 0 ||
inst_id >= FPGA_I2C_NUM_INST) {
return BF_FPGA_EINVAL;
}
/* aligned (upto) 4 bytes can be read without stopping the ongoing i2c,
* this is guaranteed by FPGA design. i2c has to be stopped, in all other
* cases, to read a consistent set of read-data.
*/
if ((offset % 4 == 0) && (num_rd <= 4)) {
return (
fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf));
}
/* non-aligned case; stop i2c if running, read data and restart i2c */
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
/* check if i2c_controller is running */
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
i2c_running = ((val & I2C_STS_BUSY) ? true : false);
if (i2c_running) {
/* stop ongoing i2c operations */
fpga_i2c_stop_locked(i2c_ctrl);
}
ret = fpga_i2c_data_read_locked(i2c_ctrl, inst_id, offset, num_rd, rd_buf);
if (i2c_running) {
/* restart ongoing i2c operations */
fpga_i2c_start_locked(i2c_ctrl);
}
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
/** FPGA I2C onetime i2c operation
*
* @param i2c_op
* bf_fpga_i2c_t parameters * <in/out>
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op) {
int i, ret;
uint32_t val;
int bus_id;
fpga_i2c_controller_t *i2c_ctrl;
if (!i2c_op) {
return BF_FPGA_EINVAL;
}
bus_id = i2c_op->inst_hndl.bus_id;
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (i2c_op->num_i2c == 0 || i2c_op->num_i2c >= FPGA_I2C_ONESHOT_NUM_INST ||
i2c_op->one_time == 0 || bus_id >= BF_I2C_FPGA_NUM_CTRL || !i2c_ctrl) {
return BF_FPGA_EINVAL;
}
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
/* stop ongoing i2c operations */
ret = fpga_i2c_stop_locked(i2c_ctrl);
if (ret) {
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
/* populate one time i2c operation instruction(s) from offset zero */
for (i = 0; i < i2c_op->num_i2c; i++) {
ret = fpga_i2c_enqueue(bus_id, i, &i2c_op->i2c_inst[i]);
if (ret) {
goto oneshot_error_exit;
}
}
/* start i2c operations */
ret = fpga_i2c_start_locked(i2c_ctrl);
if (ret) {
goto oneshot_error_exit;
}
/* wait until complete and read the data if necessary */
for (i = 0; i < i2c_op->num_i2c; i++) {
int cnt;
val = 0;
/* cnt is roughly the number of bytes of this i2c cycle
* overhead of 100 bytes for for worst case timeout, one
* should not hit that in normal working case
*/
cnt = i2c_op->i2c_inst[i].wr_cnt + i2c_op->i2c_inst[i].rd_cnt;
/* bump up the cnt for an i2c transaction containing some data
* for computing worst case timeout */
if (cnt > 0) {
cnt = cnt + 100;
}
while (!(val & I2C_STATUS_COMPLETED) && (cnt-- > 0)) {
/* 1 byte ~= 10 bits takes 25 microsec on i2c cycle at 400khz */
bf_fpga_us_delay(50);
val = fpga_i2c_get_status(bus_id, i);
}
i2c_op->i2c_inst[i].status = val; /* store the h/w status */
if (val & I2C_STATUS_ERR_MASK) {
ret = BF_FPGA_EIO;
goto oneshot_error_exit;
}
if (i2c_op->i2c_inst[i].rd_cnt) {
uint8_t offset = 0;
if (i2c_op->i2c_inst[i].wr_cnt > 1) {
offset = i2c_op->i2c_inst[i].wr_cnt - 1;
}
if (fpga_i2c_data_read_locked(i2c_ctrl,
i,
offset,
i2c_op->i2c_inst[i].rd_cnt,
i2c_op->i2c_inst[i].rd_buf)) {
ret = BF_FPGA_EIO;
goto oneshot_error_exit;
}
}
}
ret = BF_FPGA_OK;
oneshot_error_exit:
for (i = 0; i < i2c_op->num_i2c; i++) {
/* cleanup the enable bit */
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i));
val &= (~I2C_INST_EN);
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), val);
}
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
/** FPGA I2C insert periodic i2c operation
*
* @param i2c_op
* bf_fpga_i2c_t parameters * <in/out>
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op) {
fpga_i2c_controller_t *i2c_ctrl;
int i, ret, next_id;
bool preemt;
if (!i2c_op) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id);
if (!i2c_ctrl) {
return BF_FPGA_EINVAL;
}
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
/* get the next available free slot */
next_id = get_next_free_index(i2c_ctrl, i2c_op->num_i2c, true);
if (next_id < 0) {
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_EBUSY;
}
/* populate periodic i2c operation instruction(s) */
for (i = 0; i < i2c_op->num_i2c; i++) {
preemt = ((i == (i2c_op->num_i2c - 1)) ? false : true);
i2c_op->i2c_inst[i].preemt = preemt;
ret = fpga_i2c_enqueue(
i2c_op->inst_hndl.bus_id, next_id + i, &i2c_op->i2c_inst[i]);
if (ret) {
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
}
bf_fpga_i2c_unlock(i2c_ctrl);
i2c_op->inst_hndl.inst_id = next_id;
return BF_FPGA_OK;
}
/** FPGA I2C remove periodic i2c operation(s) from instruction memory
*
* @param i2c_op
* bf_fpga_i2c_t parameters * <in/out>
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_del(bf_fpga_i2c_t *i2c_op) {
fpga_i2c_controller_t *i2c_ctrl;
int i, inst_id;
if (!i2c_op) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(i2c_op->inst_hndl.bus_id);
if (!i2c_ctrl) {
return BF_FPGA_EINVAL;
}
inst_id = i2c_op->inst_hndl.inst_id;
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
for (i = 0; i < i2c_op->num_i2c; i++) {
/* nullify the instruction */
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id + i), 0);
}
/* reset the in_use flag */
release_index(i2c_ctrl, inst_id, i2c_op->num_i2c);
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_OK;
}

View File

@ -0,0 +1,55 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_I2C_H
#define _BF_FPGA_I2C_H
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
int fpga_i2c_start(int bus_id);
int fpga_i2c_stop(int bus_id);
int fpga_i2c_reset(int bus_id);
int fpga_i2c_is_busy(int bus_id, bool *is_busy);
int fpga_i2c_inst_en(int bus_id, int inst_id, bool en);
int fpga_i2c_set_clk(int bus_id, int clock_div);
int fpga_i2c_controller_init(int bus_id);
int fpga_i2c_controller_cleanup(int bus_id);
int fpga_i2c_init(uint8_t *base_addr);
void fpga_i2c_deinit(void);
int fpga_i2c_oneshot(bf_fpga_i2c_t *i2c_op);
int fpga_i2c_pr_add(bf_fpga_i2c_t *i2c_op);
int fpga_i2c_del(bf_fpga_i2c_t *i2c_op);
int fpga_i2c_data_read(
int bus_id, int inst_id, uint8_t offset, uint8_t len, uint8_t *buf);
bool fpga_i2c_is_inited(void);
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* _BF_FPGA_I2C_H */

View File

@ -0,0 +1,397 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#include <linux/types.h>
#include "bf_fpga_i2c_priv_porting.h"
#include <bf_fpga_ioctl.h>
#include "bf_fpga_i2c.h"
#include "bf_fpga_i2c_priv.h"
#include "bf_fpga_i2c_reg.h"
/* static i2c controller contents */
static fpga_i2c_controller_t fpga_i2c_ctrl[BF_I2C_FPGA_NUM_CTRL];
static bool fpga_i2c_inited = false;
/* fpga memory space access APIs */
/* 32 bit write into fpga BAR0 */
void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint32_t val) {
uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset;
bf_fpga_write32(ptr, val);
}
/* 32 bit read into fpga BAR0 */
uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset) {
uint8_t *ptr = i2c_ctrl->fpga_base_addr + offset;
return (bf_fpga_read32(ptr));
}
/* 32 bit write into fpga i2c space */
void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint32_t val) {
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
bf_fpga_write32(ptr, val);
}
/* 32 bit read into fpga i2c space */
uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset) {
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
return (bf_fpga_read32(ptr));
}
/* 8 bit write into fpga i2c space */
void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint8_t val) {
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
bf_fpga_write8(ptr, val);
}
/* 8 bit read into fpga i2c space */
uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset) {
uint8_t *ptr = i2c_ctrl->i2c_base_addr + offset;
return (bf_fpga_read8(ptr));
}
int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl) {
return (bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock));
}
void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl) {
return (bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock));
}
/** FPGA return pointer to i2c_controller struct
*
* @param bus_id
* i2c controller id
* @return
* pointer to i2c_controller struct of <bus_id>
*/
fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id) {
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
return NULL;
} else {
return &fpga_i2c_ctrl[bus_id];
}
}
/* is fpga module is soft inited */
bool fpga_i2c_is_inited() { return fpga_i2c_inited; }
/** FPGA I2C set clock: sets clock of i2c operations
*
* controller must be stopped before, if applicable.
*
* @param bus_id
* i2c controller id
* @param clk_div
* clock divider value as per fpga specs
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_set_clk(int bus_id, int clk_div) {
uint32_t val;
fpga_i2c_controller_t *i2c_ctrl;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
clk_div = (clk_div & I2C_CTRL_CLK_DIV_MASK) << I2C_CTRL_CLK_DIV_SHF;
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
val &= ~(I2C_CTRL_CLK_DIV_MASK << I2C_CTRL_CLK_DIV_SHF);
val |= clk_div;
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val);
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_OK;
}
/** FPGA I2C stop : stops ongoing i2c operations without mutex locking
*
* internal function
*
* @param bus_id
* i2c controller struct
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl) {
int to_ms, ret;
uint8_t val;
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
val &= ~I2C_CTRL_START;
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val);
to_ms = 100; /* 5 msec converted to multiple of 50 micro sec */
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
while ((val & I2C_STS_BUSY) && to_ms) {
bf_fpga_us_delay(50);
to_ms--;
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
}
if (to_ms > 0) {
ret = BF_FPGA_OK;
} else {
ret = BF_FPGA_EIO;
}
return ret;
}
/** FPGA I2C start : starts i2c operations without mutex locking
*
* internal function
*
* @param bus_id
* i2c controller struct
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl) {
uint8_t val;
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP);
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, val | I2C_CTRL_START);
return BF_FPGA_OK;
}
/** FPGA I2C stop : stops ongoing i2c operations
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_stop(int bus_id) {
fpga_i2c_controller_t *i2c_ctrl;
int ret;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
ret = fpga_i2c_stop_locked(i2c_ctrl);
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
/** FPGA I2C start : starts i2c operations
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_start(int bus_id) {
fpga_i2c_controller_t *i2c_ctrl;
int ret;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
ret = fpga_i2c_start_locked(i2c_ctrl);
bf_fpga_i2c_unlock(i2c_ctrl);
return ret;
}
/** FPGA I2C reset: reset i2c by issuing 9 clocks in a specific way
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_reset(int bus_id) {
fpga_i2c_controller_t *i2c_ctrl;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
bf_fpga_i2c_reg_write8(i2c_ctrl, Bf_FPGA_I2C_CTRL_TOP, I2C_CTRL_RESET);
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_OK;
}
/** FPGA I2C is running?
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_is_busy(int bus_id, bool *busy) {
uint8_t val;
fpga_i2c_controller_t *i2c_ctrl;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
val = bf_fpga_i2c_reg_read8(i2c_ctrl, Bf_FPGA_TOP_I2C_STATUS);
*busy = ((val & I2C_STS_BUSY) ? true : false);
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_OK;
}
/** FPGA I2C instruction enable/disable
*
* enable or disable a particular instruction in i2c instruction memory
* @param bus_id
* i2c controller id
* @param inst_id
* instruction id within this controller space
* @param en
* true for enable, false for disable
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_inst_en(int bus_id, int inst_id, bool en) {
uint32_t val;
fpga_i2c_controller_t *i2c_ctrl;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL || !fpga_i2c_is_inited()) {
return BF_FPGA_EINVAL;
}
if (inst_id < 0 || inst_id >= FPGA_I2C_NUM_INST) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (bf_fpga_i2c_lock(i2c_ctrl)) {
return BF_FPGA_EAGAIN;
}
val = bf_fpga_i2c_reg_read32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id));
if (en) {
val |= I2C_INST_EN;
} else {
val &= ~I2C_INST_EN;
}
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(inst_id), val);
fpga_i2c_ctrl[bus_id].i2c_inst[inst_id].en = en;
bf_fpga_i2c_unlock(i2c_ctrl);
return BF_FPGA_OK;
}
/** FPGA I2C controller initialization
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_controller_init(int bus_id) {
fpga_i2c_controller_t *i2c_ctrl;
int i, ret;
if (bus_id >= BF_I2C_FPGA_NUM_CTRL) {
return BF_FPGA_EINVAL;
}
i2c_ctrl = fpga_i2c_ctrl_get(bus_id);
if (!i2c_ctrl) {
return BF_FPGA_EINVAL;
}
bf_fpga_fast_lock_init(&i2c_ctrl->spinlock, 0);
bf_fpga_cr_init(&i2c_ctrl->fpga_ctrl_lock);
bf_fpga_cr_enter(&i2c_ctrl->fpga_ctrl_lock);
for (i = 0; i < FPGA_I2C_NUM_INST; i++) {
fpga_i2c_ctrl[bus_id].i2c_inst[i].inst = (uint32_t)i;
bf_fpga_i2c_reg_write32(i2c_ctrl, Bf_FPGA_I2C_INST_CTRL(i), 0);
}
bf_fpga_cr_leave(&i2c_ctrl->fpga_ctrl_lock);
ret = fpga_i2c_set_clk(bus_id, 1); /* 400 khz default */
ret |= fpga_i2c_stop(bus_id); /* just in case */
return ret;
}
/** FPGA I2C controller de initialization
*
* @param bus_id
* i2c controller id
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_controller_cleanup(int bus_id) {
int i;
fpga_i2c_stop(bus_id);
for (i = 0; i < FPGA_I2C_NUM_INST; i++) {
fpga_i2c_ctrl[bus_id].i2c_inst[i].en = false;
}
bf_fpga_cr_destroy(&fpga_i2c_ctrl[bus_id].fpga_ctrl_lock);
bf_fpga_fast_lock_destroy(&fpga_i2c_ctrl[bus_id].spinlock);
return BF_FPGA_OK;
}
/** FPGA I2C global initialization
*
* @param base_addr
* virtual address of i2c memory relative to BAR0 base
* @return
* 0 on success and <0 on error
*/
int fpga_i2c_init(uint8_t *base_addr) {
int i;
memset(fpga_i2c_ctrl, 0, sizeof(fpga_i2c_ctrl));
for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) {
fpga_i2c_ctrl[i].i2c_base_addr = base_addr + BF_FPGA_I2C_CTRL_BASE_ADDR(i);
fpga_i2c_ctrl[i].fpga_base_addr = base_addr;
fpga_i2c_controller_init(i);
}
fpga_i2c_inited = true;
return BF_FPGA_OK;
}
/** FPGA I2C global de initialization
*
*/
void fpga_i2c_deinit(void) {
int i;
for (i = 0; i < BF_I2C_FPGA_NUM_CTRL; i++) {
fpga_i2c_controller_cleanup(i);
}
fpga_i2c_inited = false;
}

View File

@ -0,0 +1,150 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
#include "bf_fpga_i2c_priv_porting.h"
#include <bf_fpga_ioctl.h>
#include "bf_fpga_i2c.h"
#include "bf_fpga_i2c_priv.h"
/* This file contains OS and system specific porting functions for i2c APIs.
* Implementation in this file is for porting to linux kernel.
*/
/* mutex APIs are for mutual exclusion with capability to sleep while in
* exclusion mode
*/
/* sleepable virtual exclusion region */
typedef struct {
atomic_t lock_state; /* 1: in exclusion mode, 0: not in exclusion mode */
} sleepable_v_mutex_t;
int bf_fpga_cr_init(bf_fpga_mutex_t *lock) {
sleepable_v_mutex_t *mtx;
if (!lock) {
return -1;
}
mtx = vzalloc(sizeof(sleepable_v_mutex_t));
if (mtx) {
atomic_set(&mtx->lock_state, 0);
*lock = (bf_fpga_mutex_t *)mtx;
return 0;
} else {
*lock = NULL;
return -1;
}
}
void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock) {
if (lock && *lock) {
vfree(*lock);
*lock = NULL;
}
}
void bf_fpga_cr_leave(bf_fpga_mutex_t *lock) {
sleepable_v_mutex_t *mtx;
if (lock && *lock) {
mtx = (sleepable_v_mutex_t *)*lock;
atomic_xchg(&mtx->lock_state, 0);
}
}
int bf_fpga_cr_enter(bf_fpga_mutex_t *lock) {
sleepable_v_mutex_t *mtx;
/* All we do here is: test and set <lock_state> */
if (lock && *lock) {
int cnt = 10000; /* This will provide maximum of 500-1000 ms timeout */
mtx = (sleepable_v_mutex_t *)*lock;
while (atomic_cmpxchg(&mtx->lock_state, 0, 1) != 0) {
if (cnt-- <= 0) {
return -1; /* this is a worst case timeout situation */
}
usleep_range(50, 100); /* 50 us = about 2 bytes at 400Kbs i2c */
}
return 0;
} else {
return -1;
}
}
/* **** not implemented in current mode of locking */
int bf_fpga_mutex_trylock(bf_fpga_mutex_t *lock) {
if (lock && *lock) {
return -1;
} else {
return -1;
}
}
/* fast lock is a non-blocking busy lock, implemented with spinlock */
int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial) {
spinlock_t *slock;
(void)initial;
if (!sl) {
return -1;
}
slock = vzalloc(sizeof(spinlock_t));
if (slock) {
spin_lock_init(slock);
*sl = (bf_fpga_fast_lock_t *)slock;
return 0;
} else {
*sl = NULL;
return -1;
}
}
void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl) {
if (sl && *sl) {
vfree(*sl);
*sl = NULL;
}
}
int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl) {
if (sl && *sl) {
spin_lock(*sl);
return 0;
} else {
return -1;
}
}
void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl) {
if (sl && *sl) {
spin_unlock(*sl);
}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_I2C_PRIV_H
#define _BF_FPGA_I2C_PRIV_H
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
#define FPGA_I2C_INST_OFFSET(idx) (0x10 + (16 * idx))
typedef enum {
FGPA_I2C_NOP = 0x0,
FGPA_I2C_WR_ADDR_DATA = 0x1, /* wr: reg_addr, wr: data */
FGPA_I2C_WR_ADDR_RD_DATA = 0x2, /* wr: reg_addrss, r/s, rd: data */
FGPA_I2C_WR_ADDR = 0x3, /* wr: reg_addr */
FGPA_I2C_RD_DATA = 0x4, /* rd: data */
FGPA_I2C_MULTI_WR_RD = 0x5 /* wr: n bytes, r/s, rd: m bytes */
} i2c_cmd_type;
/* contents of each instruction instance */
typedef struct i2c_inst_cmd_s {
i2c_cmd_type i2c_cmd; /* i2x cycle type */
uint32_t data_lo; /* lower 4 bytes of data associated with this inst */
uint32_t data_hi; /* upper 4 bytes of data associated with this inst */
uint32_t us_delay; /* delay before i2c cycle */
uint8_t i2c_addr; /* i2c device address, in 7 bit format */
uint8_t reg_addr; /* 1st write byte, if present in i2c cycle */
uint8_t num_read; /* number of bytes to write excluding reg_addr */
uint8_t num_write; /* number of bytes to read */
} i2c_inst_cmd_t;
/* attributes of each instruction instance */
typedef struct i2c_inst_s {
uint32_t inst; /* index of the instruction within the controller memory */
bool en; /* is instruction enabled */
bool preemt; /* atomically execute next instruction */
bool int_en; /* enable interrupt after execution */
bool in_use; /* is this instruction currently used */
} i2c_inst_t;
typedef struct fpga_i2c_controller_s {
bf_fpga_mutex_t fpga_ctrl_lock;
bf_fpga_fast_lock_t spinlock;
uint8_t *fpga_base_addr; /* virtual address of start of fpga memory */
uint8_t *i2c_base_addr; /* virtual address of i2c controller memory */
uint32_t start; /* offset of start of i2c instruction memory */
uint32_t len; /* number of i2c instructions belonging to this i2c engine */
uint32_t clk_div; /* clock divider used by this i2c engine */
bool int_en;
i2c_inst_t i2c_inst[FPGA_I2C_NUM_INST];
} fpga_i2c_controller_t;
fpga_i2c_controller_t *fpga_i2c_ctrl_get(int bus_id);
void bf_fpga_reg_write(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint32_t val);
uint32_t bf_fpga_reg_read(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset);
void bf_fpga_i2c_reg_write32(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint32_t val);
uint32_t bf_fpga_i2c_reg_read32(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset);
void bf_fpga_i2c_reg_write8(fpga_i2c_controller_t *i2c_ctrl,
uint32_t offset,
uint8_t val);
uint8_t bf_fpga_i2c_reg_read8(fpga_i2c_controller_t *i2c_ctrl, uint32_t offset);
int bf_fpga_i2c_lock(fpga_i2c_controller_t *i2c_ctrl);
void bf_fpga_i2c_unlock(fpga_i2c_controller_t *i2c_ctrl);
int fpga_i2c_start_locked(fpga_i2c_controller_t *i2c_ctrl);
int fpga_i2c_stop_locked(fpga_i2c_controller_t *i2c_ctrl);
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* _BF_FPGA_I2C_PRIV_H */

View File

@ -0,0 +1,93 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_I2C_PRIV_PORTING_H
#define _BF_FPGA_I2C_PRIV_PORTING_H
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
/* This file contains OS and system specific porting functions declarations.
*/
/* return status compliant with linux system calls */
#define BF_FPGA_OK 0
#define BF_FPGA_EINVAL (-EINVAL)
#define BF_FPGA_EIO (-EIO)
#define BF_FPGA_EBUSY (-EBUSY)
#define BF_FPGA_EAGAIN (-EAGAIN)
/* pci memory access functions */
static inline void bf_fpga_write32(uint8_t *addr, uint32_t val) {
u8 __iomem *reg_addr = addr;
writel(val, reg_addr);
}
static inline uint32_t bf_fpga_read32(uint8_t *addr) {
u8 __iomem *reg_addr = addr;
return (readl(reg_addr));
}
static inline void bf_fpga_write8(uint8_t *addr, uint8_t val) {
u8 __iomem *reg_addr = addr;
writeb(val, reg_addr);
}
static inline uint8_t bf_fpga_read8(uint8_t *addr) {
u8 __iomem *reg_addr = addr;
return (readb(reg_addr));
}
static inline void bf_fpga_us_delay(unsigned long usecs) {
usleep_range(usecs, usecs + 10);
}
/* general purpose mutual exclusion lock */
typedef void *bf_fpga_mutex_t;
/* fast_lock for locking only non-blocking and quick operations */
typedef void *bf_fpga_fast_lock_t;
/* APIs to init/enter/leave critical (exclusive access) regions */
int bf_fpga_cr_init(bf_fpga_mutex_t *lock);
void bf_fpga_cr_destroy(bf_fpga_mutex_t *lock);
int bf_fpga_cr_enter(bf_fpga_mutex_t *lock);
void bf_fpga_cr_leave(bf_fpga_mutex_t *lock);
int bf_fpga_fast_lock_init(bf_fpga_fast_lock_t *sl, unsigned int initial);
void bf_fpga_fast_lock_destroy(bf_fpga_fast_lock_t *sl);
int bf_fpga_fast_lock(bf_fpga_fast_lock_t *sl);
void bf_fpga_fast_unlock(bf_fpga_fast_lock_t *sl);
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* _BF_FPGA_I2C_PRIV_PORTING_H */

View File

@ -0,0 +1,116 @@
/*******************************************************************************
Barefoot Networks FPGA Linux driver
Copyright(c) 2018 - 2019 Barefoot Networks, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
info@barefootnetworks.com
Barefoot Networks, 4750 Patrick Henry Drive, Santa Clara CA 95054
*******************************************************************************/
#ifndef _BF_FPGA_I2C_REG_H
#define _BF_FPGA_I2C_REG_H
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C" {
#endif
/* registers outsize of all i2c controller register space */
#define BF_FPGA_I2C_BASE_ADDR 0x0
#define BF_FPGA_I2C_CTRL_BASE_ADDR(i) (BF_FPGA_I2C_BASE_ADDR + (i * 4096))
/* per i2c controller register offset relative to BF_FPGA_I2C_CTRL_BASE_ADDR */
#define Bf_FPGA_I2C_CTRL_TOP 0
#define I2C_CTRL_START (1 << 0)
#define I2C_CTRL_RESET (1 << 1)
#define I2C_CTRL_CLK_DIV_SHF (8)
#define I2C_CTRL_CLK_DIV_MASK (0x1FF)
#define Bf_FPGA_TOP_I2C_STATUS 4
#define I2C_STS_BUSY (1 << 0)
#define I2C_STS_ERR (1 << 3)
#define Bf_FPGA_I2C_INST_CTRL(i) (0x10 + (16 * i))
#define I2C_INST_EN (1 << 31)
#define I2C_INST_PMT (1 << 30)
#define I2C_TYPE_SHF (26)
#define I2C_DELAY_SHF (23)
#define I2C_STOP_ON_ERROR (22)
/* various status values */
#define I2C_STATUS_MASK 0x3F
#define I2C_STATUS_ERR_MASK 0x3C
#define I2C_STATUS_RUNNING 0x1
#define I2C_STATUS_COMPLETED 0x2
#define I2C_STATUS_NACK_ADDR 0x4
#define I2C_STATUS_NACK_CMD 0x8
#define I2C_STATUS_NACK_WR_DATA 0x10
#define I2C_STATUS_TOUT 0x20
/* i2c instruction types */
#define I2C_WR_ADDR_DATA (0 << I2C_TYPE_SHF)
#define I2C_RD_DATA (3 << I2C_TYPE_SHF)
#define I2C_WR_ADDR (2 << I2C_TYPE_SHF)
#define I2C_RD_ADDR_DATA (1 << I2C_TYPE_SHF)
#define I2C_RD_ADDR_DATA_BURST (4 << I2C_TYPE_SHF)
#define I2C_NOP (6 << I2C_TYPE_SHF)
#define Bf_FPGA_I2C_INST_PARAM(i) (0x14 + (16 * i))
#define I2C_DEV_ADDR_SHF (24)
#define I2C_CMD_OFFSET (16)
#define I2C_WR_CNT_SHF (8)
#define I2C_RD_CNT_SHF (0)
#define Bf_FPGA_I2C_INST_DATA_LO(i) (0x18 + (16 * i))
#define Bf_FPGA_I2C_INST_DATA_HI(i) (0x1C + (16 * i))
/******************
#define Bf_FPGA_I2C_PR_CTRL(i) (0x100 + (16 * i))
#define Bf_FPGA_I2C_PR_PARM(i) (0x104 + (16 * i))
#define Bf_FPGA_I2C_PR_LO(i) (0x108 + (16 * i))
#define Bf_FPGA_I2C_PR_HI(i) (0x10C + (16 * i))
******************/
/* data area pointers */
/* the driver makes fixed static allocation of the available memory
* on per instruction basis
* allocate 128 bytes per one time instruction = total 0x780 bytes
* allocate 64 bytes per one periodic instruction = total 0x400 bytes
* FPGA_I2C_ONESHOT_NUM_INST -> comes from a header file that must be included
* before this file.
*/
#define BF_FPGA_ONE_MAX_BURST 128
#define BF_FPGA_PR_MAX_BURST 64
#define BF_FPGA_I2C_DATA_AREA(i) \
((i < FPGA_I2C_ONESHOT_NUM_INST) \
? (0x200 + (i * BF_FPGA_ONE_MAX_BURST)) \
: (0x980 + ((i - FPGA_I2C_ONESHOT_NUM_INST) * BF_FPGA_PR_MAX_BURST)))
#if BF_FPGA_I2C_DATA_AREA(FPGA_I2C_PERIODIC_NUM_INST) > 0x1000
#error erroneous allocation of FPGA memory to i2c data area. Fix it!
#endif
#define BF_FPGA_VER_REG 0x3F000
#define BF_FPGA_BUILD_DATE 0x3F004
#define BF_FPGA_RESET_CTRL_1 0x3F008
#define BF_FPGA_RESET_CTRL_2 0x3F00C
#ifdef __cplusplus
}
#endif /* C++ */
#endif /* _BF_FPGA_I2C_REG_H */

View File

@ -0,0 +1,10 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS syncd sfputil "$@"

View File

@ -0,0 +1,10 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS syncd eeprom "$@"

View File

@ -0,0 +1,11 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS syncd fancontrol "$@"

View File

@ -0,0 +1,10 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS syncd ps_info "$@"

View File

@ -0,0 +1,12 @@
#!/bin/bash
DOCKER_EXEC_FLAGS="i"
# Determine whether stdout is on a terminal
if [ -t 1 ] ; then
DOCKER_EXEC_FLAGS+="t"
fi
docker exec -$DOCKER_EXEC_FLAGS syncd sensors "$@"

View File

@ -0,0 +1 @@
echo "test"