mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
Pull board-specific code into mqnic_board.c and refactor I2C code
This commit is contained in:
parent
53df02d22c
commit
6b142d36c2
@ -1,7 +1,18 @@
|
||||
|
||||
# object files to build
|
||||
obj-m += mqnic.o
|
||||
mqnic-objs += mqnic_main.o mqnic_dev.o mqnic_netdev.o mqnic_port.o mqnic_ethtool.o mqnic_i2c.o mqnic_ptp.o mqnic_tx.o mqnic_rx.o mqnic_cq.o mqnic_eq.o
|
||||
mqnic-y += mqnic_main.o
|
||||
mqnic-y += mqnic_dev.o
|
||||
mqnic-y += mqnic_netdev.o
|
||||
mqnic-y += mqnic_port.o
|
||||
mqnic-y += mqnic_ptp.o
|
||||
mqnic-y += mqnic_i2c.o
|
||||
mqnic-y += mqnic_board.o
|
||||
mqnic-y += mqnic_tx.o
|
||||
mqnic-y += mqnic_rx.o
|
||||
mqnic-y += mqnic_cq.o
|
||||
mqnic-y += mqnic_eq.o
|
||||
mqnic-y += mqnic_ethtool.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||
|
@ -50,7 +50,14 @@ either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
#include "mqnic_hw.h"
|
||||
|
||||
struct mqnic_i2c_priv
|
||||
struct mqnic_dev;
|
||||
|
||||
struct mqnic_board_ops {
|
||||
int (*init)(struct mqnic_dev *mqnic);
|
||||
void (*deinit)(struct mqnic_dev *mqnic);
|
||||
};
|
||||
|
||||
struct mqnic_i2c_bus
|
||||
{
|
||||
struct mqnic_dev *mqnic;
|
||||
|
||||
@ -63,6 +70,11 @@ struct mqnic_i2c_priv
|
||||
uint32_t scl_out_mask;
|
||||
uint32_t sda_in_mask;
|
||||
uint32_t sda_out_mask;
|
||||
|
||||
struct list_head head;
|
||||
|
||||
struct i2c_algo_bit_data algo;
|
||||
struct i2c_adapter adapter;
|
||||
};
|
||||
|
||||
struct mqnic_dev {
|
||||
@ -106,10 +118,10 @@ struct mqnic_dev {
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_info;
|
||||
|
||||
struct mqnic_board_ops *board_ops;
|
||||
|
||||
struct list_head i2c_bus;
|
||||
int i2c_adapter_count;
|
||||
struct i2c_algo_bit_data i2c_algo[MQNIC_MAX_I2C_ADAPTERS];
|
||||
struct i2c_adapter i2c_adapter[MQNIC_MAX_I2C_ADAPTERS];
|
||||
struct mqnic_i2c_priv i2c_priv[MQNIC_MAX_I2C_ADAPTERS];
|
||||
|
||||
int mod_i2c_client_count;
|
||||
struct i2c_client *mod_i2c_client[MQNIC_MAX_IF];
|
||||
@ -324,8 +336,16 @@ void mqnic_unregister_phc(struct mqnic_dev *mdev);
|
||||
ktime_t mqnic_read_cpl_ts(struct mqnic_dev *mdev, struct mqnic_ring *ring, const struct mqnic_cpl *cpl);
|
||||
|
||||
// mqnic_i2c.c
|
||||
int mqnic_init_i2c(struct mqnic_dev *mqnic);
|
||||
void mqnic_remove_i2c(struct mqnic_dev *mqnic);
|
||||
struct mqnic_i2c_bus *mqnic_i2c_bus_create(struct mqnic_dev *mqnic, u8 __iomem *reg);
|
||||
struct i2c_adapter *mqnic_i2c_adapter_create(struct mqnic_dev *mqnic, u8 __iomem *reg);
|
||||
void mqnic_i2c_bus_release(struct mqnic_i2c_bus *bus);
|
||||
void mqnic_i2c_adapter_release(struct i2c_adapter *adapter);
|
||||
int mqnic_i2c_init(struct mqnic_dev *mqnic);
|
||||
void mqnic_i2c_deinit(struct mqnic_dev *mqnic);
|
||||
|
||||
// mqnic_board.c
|
||||
int mqnic_board_init(struct mqnic_dev *mqnic);
|
||||
void mqnic_board_deinit(struct mqnic_dev *mqnic);
|
||||
|
||||
// mqnic_eq.c
|
||||
int mqnic_create_eq_ring(struct mqnic_priv *priv, struct mqnic_eq_ring **ring_ptr, int size, int stride, int index, u8 __iomem *hw_addr);
|
||||
|
468
modules/mqnic/mqnic_board.c
Normal file
468
modules/mqnic/mqnic_board.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*
|
||||
|
||||
Copyright 2021, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#include "mqnic.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
static const struct property_entry i2c_mux_props[] = {
|
||||
PROPERTY_ENTRY_BOOL("i2c-mux-idle-disconnect"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_client *create_i2c_client(struct i2c_adapter *adapter, const char *type, int addr, const struct property_entry *props)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info board_info;
|
||||
int err;
|
||||
|
||||
if (!adapter)
|
||||
return NULL;
|
||||
|
||||
memset(&board_info, 0, sizeof(board_info));
|
||||
strscpy(board_info.type, type, I2C_NAME_SIZE);
|
||||
board_info.addr = addr;
|
||||
board_info.properties = props;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)
|
||||
client = i2c_new_client_device(adapter, &board_info);
|
||||
#else
|
||||
client = i2c_new_device(adapter, &board_info);
|
||||
#endif
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
// force driver load (mainly for muxes so we can talk to downstream devices)
|
||||
err = device_attach(&client->dev);
|
||||
if (err < 0)
|
||||
goto err_free_client;
|
||||
|
||||
return client;
|
||||
|
||||
err_free_client:
|
||||
i2c_unregister_device(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct i2c_adapter *get_i2c_mux_channel(struct i2c_client *mux, u32 chan_id)
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
|
||||
if (!mux)
|
||||
return NULL;
|
||||
|
||||
muxc = i2c_get_clientdata(mux);
|
||||
|
||||
if (!muxc || chan_id >= muxc->num_adapters)
|
||||
return NULL;
|
||||
|
||||
return muxc->adapter[chan_id];
|
||||
}
|
||||
|
||||
static int read_mac_from_eeprom(struct mqnic_dev *mqnic, struct i2c_client *eeprom, int offset, char *mac)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!eeprom)
|
||||
{
|
||||
dev_warn(mqnic->dev, "Failed to read MAC from EEPROM; no EEPROM I2C client registered");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(eeprom, offset, 6, mac);
|
||||
if (ret < 0)
|
||||
{
|
||||
dev_warn(mqnic->dev, "Failed to read MAC from EEPROM");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_mac_list_from_eeprom_base(struct mqnic_dev *mqnic, struct i2c_client *eeprom, int offset, int count)
|
||||
{
|
||||
int ret, k;
|
||||
char mac[6];
|
||||
|
||||
count = min(count, MQNIC_MAX_IF);
|
||||
|
||||
ret = read_mac_from_eeprom(mqnic, eeprom, offset, mac);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!is_valid_ether_addr(mac))
|
||||
{
|
||||
dev_warn(mqnic->dev, "EEPROM does not contain a valid base MAC");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mqnic->mac_count = count;
|
||||
for (k = 0; k < mqnic->mac_count; k++)
|
||||
{
|
||||
memcpy(mqnic->mac_list[k], mac, ETH_ALEN);
|
||||
mqnic->mac_list[k][ETH_ALEN-1] += k;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mqnic_generic_board_init(struct mqnic_dev *mqnic)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *mux;
|
||||
int ret = 0;
|
||||
|
||||
mqnic->mod_i2c_client_count = 0;
|
||||
|
||||
if (mqnic_i2c_init(mqnic))
|
||||
{
|
||||
dev_err(mqnic->dev, "Failed to initialize I2C subsystem");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mqnic->board_id) {
|
||||
case MQNIC_BOARD_ID_NETFPGA_SUME:
|
||||
// FPGA IC12
|
||||
// TCA9548 IC31 0x74
|
||||
// CH0: SFP1 IC3 0x50
|
||||
// CH1: SFP2 IC5 0x50
|
||||
// CH2: SFP3 IC6 0x50
|
||||
// CH3: SFP4 IC8 0x50
|
||||
// CH4: DDR3 IC27 0x51
|
||||
// DDR3 IC28 0x52
|
||||
// SI5324 IC20 0x68
|
||||
// CH5: FMC
|
||||
// CH6: PCON
|
||||
// CH7: PMOD J11
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// IC31 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// IC3 SFP1
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL);
|
||||
|
||||
// IC5 SFP2
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL);
|
||||
|
||||
// IC6 SFP3
|
||||
mqnic->mod_i2c_client[2] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// IC8 SFP4
|
||||
mqnic->mod_i2c_client[3] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 4;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU108:
|
||||
// FPGA U1
|
||||
// TCA9548 U28 0x74
|
||||
// CH0: SI570 Osc U32 0x5D
|
||||
// CH1: TCA6416 Port Exp U89 0x21
|
||||
// CH2: QSFP U145 0x50
|
||||
// CH3: NC
|
||||
// CH4: SI5328 U57 0x68
|
||||
// CH5: HDMI U52 0x39
|
||||
// CH6: SYSMON U1 0x32
|
||||
// CH7: NC
|
||||
// PCA9544 U80 0x75
|
||||
// CH0: PMBUS
|
||||
// CH1: FMC_HPC0 J22
|
||||
// CH2: FMC_HPC1 J2
|
||||
// CH3: M24C08 EEPROM U12 0x54
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U145 QSFP
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// U80 PCA9544 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9544", 0x75, i2c_mux_props);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 1;
|
||||
|
||||
// read MACs from EEPROM
|
||||
init_mac_list_from_eeprom_base(mqnic, mqnic->eeprom_i2c_client, 0, MQNIC_MAX_IF);
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU118:
|
||||
// FPGA U1
|
||||
// TCA9548 U28 0x74
|
||||
// CH0: SI570 Osc U32 0x5D
|
||||
// CH1: NC
|
||||
// CH2: QSFP1 U145 0x50
|
||||
// CH3: QSFP2 U123 0x50
|
||||
// CH4: SI5328 U57 0x68
|
||||
// CH5: SI570 Osc U18 0x5D
|
||||
// CH6: SYSMON U1 0x32
|
||||
// CH7: FIREFLY J6 0x50
|
||||
// TCA9548 U80 0x75
|
||||
// CH0: PMBUS
|
||||
// CH1: FMCP_HSPC J22
|
||||
// CH2: FMC_HPC1 J2
|
||||
// CH3: M24C08 EEPROM U12 0x54
|
||||
// CH4: INA_PMBUS
|
||||
// CH5: SI570 Osc U38 0x5D
|
||||
// CH6: NC
|
||||
// CH7: NC
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U145 QSFP1
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// U123 QSFP2
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL);
|
||||
|
||||
// U80 PCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
// read MACs from EEPROM
|
||||
init_mac_list_from_eeprom_base(mqnic, mqnic->eeprom_i2c_client, 0, MQNIC_MAX_IF);
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU1525:
|
||||
case MQNIC_BOARD_ID_AU200:
|
||||
case MQNIC_BOARD_ID_AU250:
|
||||
// FPGA U13
|
||||
// PCA9546 U28 0x74
|
||||
// CH0: QSFP0 J7 0x50
|
||||
// CH1: QSFP1 J9 0x50
|
||||
// CH2: M24C08 EEPROM U62 0x54
|
||||
// SI570 Osc U14 0x5D
|
||||
// CH3: SYSMON U13 0x32
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9546 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9546", 0x74, i2c_mux_props);
|
||||
|
||||
// J7 QSFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL);
|
||||
|
||||
// J9 QSFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
// read MACs from EEPROM
|
||||
init_mac_list_from_eeprom_base(mqnic, mqnic->eeprom_i2c_client, 0, MQNIC_MAX_IF);
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_ZCU106:
|
||||
// FPGA U1 / MSP430 U41 I2C0
|
||||
// TCA6416 U61 0x21
|
||||
// TCA6416 U97 0x20
|
||||
// PCA9544 U60 0x75
|
||||
// CH0: PS_PMBUS
|
||||
// CH1: PL_PMBUS
|
||||
// CH2: MAXIM_PMBUS
|
||||
// CH3: SYSMON U1 0x32
|
||||
// FPGA U1 / MSP430 U41 I2C1
|
||||
// TCA9548 U34 0x74
|
||||
// CH0: M24C08 EEPROM U23 0x54
|
||||
// CH1: SI5341 U69 0x36
|
||||
// CH2: SI570 Osc U42 0x5D
|
||||
// CH3: SI570 Osc U56 0x5D
|
||||
// CH4: SI5328 U20 0x68
|
||||
// CH5: NC
|
||||
// CH6: NC
|
||||
// CH7: NC
|
||||
// TCA9548 U135 0x75
|
||||
// CH0: FMC_HPC0 J5
|
||||
// CH1: FMC_HPC1 J4
|
||||
// CH2: SYSMON U1 0x32
|
||||
// CH3: DDR4 SODIMM 0x51
|
||||
// CH4: NC
|
||||
// CH5: NC
|
||||
// CH6: SFP1 P2 0x50
|
||||
// CH7: SFP0 P1 0x50
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U34 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U23 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c08", 0x54, NULL);
|
||||
|
||||
// U135 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props);
|
||||
|
||||
// P1 SFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 7), "24c02", 0x50, NULL);
|
||||
|
||||
// P2 SFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 6), "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
// read MACs from EEPROM
|
||||
init_mac_list_from_eeprom_base(mqnic, mqnic->eeprom_i2c_client, 0, MQNIC_MAX_IF);
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_FB2CG_KU15P:
|
||||
// FPGA U1 I2C0
|
||||
// QSFP0 J3 0x50
|
||||
// FPGA U1 I2C1
|
||||
// QSFP1 J4 0x50
|
||||
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// QSFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_1);
|
||||
|
||||
// QSFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_EXANIC_X10:
|
||||
case MQNIC_BOARD_ID_EXANIC_X25:
|
||||
case MQNIC_BOARD_ID_ADM_PCIE_9V3:
|
||||
|
||||
// create I2C adapter
|
||||
adapter = mqnic_i2c_adapter_create(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_1);
|
||||
|
||||
// I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
// read MACs from EEPROM
|
||||
init_mac_list_from_eeprom_base(mqnic, mqnic->eeprom_i2c_client, 0, MQNIC_MAX_IF);
|
||||
|
||||
break;
|
||||
default:
|
||||
dev_warn(mqnic->dev, "Unknown board ID, not performing any board-specific init");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mqnic_generic_board_deinit(struct mqnic_dev *mqnic)
|
||||
{
|
||||
int k;
|
||||
|
||||
// unregister I2C clients
|
||||
for (k = 0; k < ARRAY_SIZE(mqnic->mod_i2c_client); k++)
|
||||
{
|
||||
if (mqnic->mod_i2c_client[k])
|
||||
{
|
||||
i2c_unregister_device(mqnic->mod_i2c_client[k]);
|
||||
mqnic->mod_i2c_client[k] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mqnic->eeprom_i2c_client)
|
||||
{
|
||||
i2c_unregister_device(mqnic->eeprom_i2c_client);
|
||||
mqnic->eeprom_i2c_client = NULL;
|
||||
}
|
||||
|
||||
mqnic_i2c_deinit(mqnic);
|
||||
}
|
||||
|
||||
static struct mqnic_board_ops generic_board_ops = {
|
||||
.init = mqnic_generic_board_init,
|
||||
.deinit = mqnic_generic_board_deinit
|
||||
};
|
||||
|
||||
int mqnic_board_init(struct mqnic_dev *mqnic)
|
||||
{
|
||||
switch (mqnic->board_id) {
|
||||
default:
|
||||
mqnic->board_ops = &generic_board_ops;
|
||||
}
|
||||
|
||||
if (!mqnic->board_ops)
|
||||
return -1;
|
||||
|
||||
return mqnic->board_ops->init(mqnic);
|
||||
}
|
||||
|
||||
void mqnic_board_deinit(struct mqnic_dev *mqnic)
|
||||
{
|
||||
if (!mqnic->board_ops)
|
||||
return;
|
||||
|
||||
mqnic->board_ops->deinit(mqnic);
|
||||
}
|
@ -32,142 +32,86 @@ either expressed or implied, of The Regents of the University of California.
|
||||
*/
|
||||
|
||||
#include "mqnic.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
static void mqnic_i2c_set_scl(void *data, int state)
|
||||
{
|
||||
struct mqnic_i2c_priv *priv = data;
|
||||
struct mqnic_i2c_bus *bus = data;
|
||||
|
||||
if (state)
|
||||
{
|
||||
iowrite32(ioread32(priv->scl_out_reg) | priv->scl_out_mask, priv->scl_out_reg);
|
||||
iowrite32(ioread32(bus->scl_out_reg) | bus->scl_out_mask, bus->scl_out_reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
iowrite32(ioread32(priv->scl_out_reg) & ~priv->scl_out_mask, priv->scl_out_reg);
|
||||
iowrite32(ioread32(bus->scl_out_reg) & ~bus->scl_out_mask, bus->scl_out_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqnic_i2c_set_sda(void *data, int state)
|
||||
{
|
||||
struct mqnic_i2c_priv *priv = data;
|
||||
struct mqnic_i2c_bus *bus = data;
|
||||
|
||||
if (state)
|
||||
{
|
||||
iowrite32(ioread32(priv->sda_out_reg) | priv->sda_out_mask, priv->sda_out_reg);
|
||||
iowrite32(ioread32(bus->sda_out_reg) | bus->sda_out_mask, bus->sda_out_reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
iowrite32(ioread32(priv->sda_out_reg) & ~priv->sda_out_mask, priv->sda_out_reg);
|
||||
iowrite32(ioread32(bus->sda_out_reg) & ~bus->sda_out_mask, bus->sda_out_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int mqnic_i2c_get_scl(void *data)
|
||||
{
|
||||
struct mqnic_i2c_priv *priv = data;
|
||||
struct mqnic_i2c_bus *bus = data;
|
||||
|
||||
return !!(ioread32(priv->scl_in_reg) & priv->scl_in_mask);
|
||||
return !!(ioread32(bus->scl_in_reg) & bus->scl_in_mask);
|
||||
}
|
||||
|
||||
static int mqnic_i2c_get_sda(void *data)
|
||||
{
|
||||
struct mqnic_i2c_priv *priv = data;
|
||||
struct mqnic_i2c_bus *bus = data;
|
||||
|
||||
return !!(ioread32(priv->sda_in_reg) & priv->sda_in_mask);
|
||||
return !!(ioread32(bus->sda_in_reg) & bus->sda_in_mask);
|
||||
}
|
||||
|
||||
static const struct i2c_algo_bit_data mqnic_i2c_algo = {
|
||||
.setsda = mqnic_i2c_set_sda,
|
||||
.setscl = mqnic_i2c_set_scl,
|
||||
.getsda = mqnic_i2c_get_sda,
|
||||
.getscl = mqnic_i2c_get_scl,
|
||||
.udelay = 5,
|
||||
.timeout = 20
|
||||
};
|
||||
|
||||
static const struct property_entry i2c_mux_props[] = {
|
||||
PROPERTY_ENTRY_BOOL("i2c-mux-idle-disconnect"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_client *create_i2c_client(struct i2c_adapter *adapter, const char *type, int addr, const struct property_entry *props)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct i2c_board_info board_info;
|
||||
int err;
|
||||
|
||||
if (!adapter)
|
||||
return NULL;
|
||||
|
||||
memset(&board_info, 0, sizeof(board_info));
|
||||
strscpy(board_info.type, type, I2C_NAME_SIZE);
|
||||
board_info.addr = addr;
|
||||
board_info.properties = props;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)
|
||||
client = i2c_new_client_device(adapter, &board_info);
|
||||
#else
|
||||
client = i2c_new_device(adapter, &board_info);
|
||||
#endif
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
// force driver load (mainly for muxes so we can talk to downstream devices)
|
||||
err = device_attach(&client->dev);
|
||||
if (err < 0)
|
||||
goto err_free_client;
|
||||
|
||||
return client;
|
||||
|
||||
err_free_client:
|
||||
i2c_unregister_device(client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct i2c_adapter *get_i2c_mux_channel(struct i2c_client *mux, u32 chan_id)
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
|
||||
if (!mux)
|
||||
return NULL;
|
||||
|
||||
muxc = i2c_get_clientdata(mux);
|
||||
|
||||
if (!muxc || chan_id >= muxc->num_adapters)
|
||||
return NULL;
|
||||
|
||||
return muxc->adapter[chan_id];
|
||||
}
|
||||
|
||||
static struct i2c_adapter *mqnic_create_i2c_adapter(struct mqnic_dev *mqnic, u8 __iomem *reg)
|
||||
struct mqnic_i2c_bus *mqnic_i2c_bus_create(struct mqnic_dev *mqnic, u8 __iomem *reg)
|
||||
{
|
||||
struct mqnic_i2c_bus *bus;
|
||||
struct i2c_algo_bit_data *algo;
|
||||
struct i2c_adapter *adapter;
|
||||
struct mqnic_i2c_priv *priv;
|
||||
|
||||
if (mqnic->i2c_adapter_count >= MQNIC_MAX_I2C_ADAPTERS || !reg)
|
||||
if (!reg)
|
||||
return NULL;
|
||||
|
||||
algo = &mqnic->i2c_algo[mqnic->i2c_adapter_count];
|
||||
adapter = &mqnic->i2c_adapter[mqnic->i2c_adapter_count];
|
||||
priv = &mqnic->i2c_priv[mqnic->i2c_adapter_count];
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
|
||||
priv->mqnic = mqnic;
|
||||
priv->scl_in_reg = reg;
|
||||
priv->scl_out_reg = reg;
|
||||
priv->sda_in_reg = reg;
|
||||
priv->sda_out_reg = reg;
|
||||
priv->scl_in_mask = MQNIC_REG_GPIO_I2C_SCL_IN;
|
||||
priv->scl_out_mask = MQNIC_REG_GPIO_I2C_SCL_OUT;
|
||||
priv->sda_in_mask = MQNIC_REG_GPIO_I2C_SDA_IN;
|
||||
priv->sda_out_mask = MQNIC_REG_GPIO_I2C_SDA_OUT;
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
*algo = mqnic_i2c_algo;
|
||||
algo->data = priv;
|
||||
// set private data
|
||||
bus->mqnic = mqnic;
|
||||
bus->scl_in_reg = reg;
|
||||
bus->scl_out_reg = reg;
|
||||
bus->sda_in_reg = reg;
|
||||
bus->sda_out_reg = reg;
|
||||
bus->scl_in_mask = MQNIC_REG_GPIO_I2C_SCL_IN;
|
||||
bus->scl_out_mask = MQNIC_REG_GPIO_I2C_SCL_OUT;
|
||||
bus->sda_in_mask = MQNIC_REG_GPIO_I2C_SDA_IN;
|
||||
bus->sda_out_mask = MQNIC_REG_GPIO_I2C_SDA_OUT;
|
||||
|
||||
// bit-bang algorithm setup
|
||||
algo = &bus->algo;
|
||||
algo->udelay = 5;
|
||||
algo->timeout = usecs_to_jiffies(2000);;
|
||||
algo->setsda = mqnic_i2c_set_sda;
|
||||
algo->setscl = mqnic_i2c_set_scl;
|
||||
algo->getsda = mqnic_i2c_get_sda;
|
||||
algo->getscl = mqnic_i2c_get_scl;
|
||||
algo->data = bus;
|
||||
|
||||
// adapter setup
|
||||
adapter = &bus->adapter;
|
||||
adapter->owner = THIS_MODULE;
|
||||
adapter->algo_data = algo;
|
||||
adapter->dev.parent = mqnic->dev;
|
||||
@ -176,325 +120,69 @@ static struct i2c_adapter *mqnic_create_i2c_adapter(struct mqnic_dev *mqnic, u8
|
||||
if (i2c_bit_add_bus(adapter))
|
||||
{
|
||||
dev_err(mqnic->dev, "Failed to register I2C adapter");
|
||||
memset(adapter, 0, sizeof(*adapter));
|
||||
return NULL;
|
||||
goto err_free_bus;
|
||||
}
|
||||
|
||||
list_add_tail(&bus->head, &mqnic->i2c_bus);
|
||||
|
||||
mqnic->i2c_adapter_count++;
|
||||
|
||||
return adapter;
|
||||
return bus;
|
||||
|
||||
err_free_bus:
|
||||
kfree(bus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mqnic_init_i2c(struct mqnic_dev *mqnic)
|
||||
struct i2c_adapter *mqnic_i2c_adapter_create(struct mqnic_dev *mqnic, u8 __iomem *reg)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *mux;
|
||||
int ret = 0;
|
||||
struct mqnic_i2c_bus *bus = mqnic_i2c_bus_create(mqnic, reg);
|
||||
|
||||
mqnic->mod_i2c_client_count = 0;
|
||||
if (!bus)
|
||||
return NULL;
|
||||
|
||||
// Interface I2C bus
|
||||
switch (mqnic->board_id) {
|
||||
case MQNIC_BOARD_ID_NETFPGA_SUME:
|
||||
// FPGA IC12
|
||||
// TCA9548 IC31 0x74
|
||||
// CH0: SFP1 IC3 0x50
|
||||
// CH1: SFP2 IC5 0x50
|
||||
// CH2: SFP3 IC6 0x50
|
||||
// CH3: SFP4 IC8 0x50
|
||||
// CH4: DDR3 IC27 0x51
|
||||
// DDR3 IC28 0x52
|
||||
// SI5324 IC20 0x68
|
||||
// CH5: FMC
|
||||
// CH6: PCON
|
||||
// CH7: PMOD J11
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// IC31 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// IC3 SFP1
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL);
|
||||
|
||||
// IC5 SFP2
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL);
|
||||
|
||||
// IC6 SFP3
|
||||
mqnic->mod_i2c_client[2] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// IC8 SFP4
|
||||
mqnic->mod_i2c_client[3] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 4;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU108:
|
||||
// FPGA U1
|
||||
// TCA9548 U28 0x74
|
||||
// CH0: SI570 Osc U32 0x5D
|
||||
// CH1: TCA6416 Port Exp U89 0x21
|
||||
// CH2: QSFP U145 0x50
|
||||
// CH3: NC
|
||||
// CH4: SI5328 U57 0x68
|
||||
// CH5: HDMI U52 0x39
|
||||
// CH6: SYSMON U1 0x32
|
||||
// CH7: NC
|
||||
// PCA9544 U80 0x75
|
||||
// CH0: PMBUS
|
||||
// CH1: FMC_HPC0 J22
|
||||
// CH2: FMC_HPC1 J2
|
||||
// CH3: M24C08 EEPROM U12 0x54
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U145 QSFP
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// U80 PCA9544 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9544", 0x75, i2c_mux_props);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 1;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU118:
|
||||
// FPGA U1
|
||||
// TCA9548 U28 0x74
|
||||
// CH0: SI570 Osc U32 0x5D
|
||||
// CH1: NC
|
||||
// CH2: QSFP1 U145 0x50
|
||||
// CH3: QSFP2 U123 0x50
|
||||
// CH4: SI5328 U57 0x68
|
||||
// CH5: SI570 Osc U18 0x5D
|
||||
// CH6: SYSMON U1 0x32
|
||||
// CH7: FIREFLY J6 0x50
|
||||
// TCA9548 U80 0x75
|
||||
// CH0: PMBUS
|
||||
// CH1: FMCP_HSPC J22
|
||||
// CH2: FMC_HPC1 J2
|
||||
// CH3: M24C08 EEPROM U12 0x54
|
||||
// CH4: INA_PMBUS
|
||||
// CH5: SI570 Osc U38 0x5D
|
||||
// CH6: NC
|
||||
// CH7: NC
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U145 QSFP1
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c02", 0x50, NULL);
|
||||
|
||||
// U123 QSFP2
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c02", 0x50, NULL);
|
||||
|
||||
// U80 PCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 3), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_VCU1525:
|
||||
case MQNIC_BOARD_ID_AU200:
|
||||
case MQNIC_BOARD_ID_AU250:
|
||||
// FPGA U13
|
||||
// PCA9546 U28 0x74
|
||||
// CH0: QSFP0 J7 0x50
|
||||
// CH1: QSFP1 J9 0x50
|
||||
// CH2: M24C08 EEPROM U62 0x54
|
||||
// SI570 Osc U14 0x5D
|
||||
// CH3: SYSMON U13 0x32
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U28 TCA9546 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9546", 0x74, i2c_mux_props);
|
||||
|
||||
// J7 QSFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c02", 0x50, NULL);
|
||||
|
||||
// J9 QSFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 1), "24c02", 0x50, NULL);
|
||||
|
||||
// U12 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 2), "24c08", 0x54, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_ZCU106:
|
||||
// FPGA U1 / MSP430 U41 I2C0
|
||||
// TCA6416 U61 0x21
|
||||
// TCA6416 U97 0x20
|
||||
// PCA9544 U60 0x75
|
||||
// CH0: PS_PMBUS
|
||||
// CH1: PL_PMBUS
|
||||
// CH2: MAXIM_PMBUS
|
||||
// CH3: SYSMON U1 0x32
|
||||
// FPGA U1 / MSP430 U41 I2C1
|
||||
// TCA9548 U34 0x74
|
||||
// CH0: M24C08 EEPROM U23 0x54
|
||||
// CH1: SI5341 U69 0x36
|
||||
// CH2: SI570 Osc U42 0x5D
|
||||
// CH3: SI570 Osc U56 0x5D
|
||||
// CH4: SI5328 U20 0x68
|
||||
// CH5: NC
|
||||
// CH6: NC
|
||||
// CH7: NC
|
||||
// TCA9548 U135 0x75
|
||||
// CH0: FMC_HPC0 J5
|
||||
// CH1: FMC_HPC1 J4
|
||||
// CH2: SYSMON U1 0x32
|
||||
// CH3: DDR4 SODIMM 0x51
|
||||
// CH4: NC
|
||||
// CH5: NC
|
||||
// CH6: SFP1 P2 0x50
|
||||
// CH7: SFP0 P1 0x50
|
||||
|
||||
request_module("i2c_mux_pca954x");
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// U34 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x74, i2c_mux_props);
|
||||
|
||||
// U23 I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(get_i2c_mux_channel(mux, 0), "24c08", 0x54, NULL);
|
||||
|
||||
// U135 TCA9548 I2C MUX
|
||||
mux = create_i2c_client(adapter, "pca9548", 0x75, i2c_mux_props);
|
||||
|
||||
// P1 SFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(get_i2c_mux_channel(mux, 7), "24c02", 0x50, NULL);
|
||||
|
||||
// P2 SFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(get_i2c_mux_channel(mux, 6), "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
break;
|
||||
case MQNIC_BOARD_ID_FB2CG_KU15P:
|
||||
// FPGA U1 I2C0
|
||||
// QSFP0 J3 0x50
|
||||
// FPGA U1 I2C1
|
||||
// QSFP1 J4 0x50
|
||||
|
||||
request_module("at24");
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_0);
|
||||
|
||||
// QSFP0
|
||||
mqnic->mod_i2c_client[0] = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
// I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_1);
|
||||
|
||||
// QSFP1
|
||||
mqnic->mod_i2c_client[1] = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
mqnic->mod_i2c_client_count = 2;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// EEPROM I2C bus
|
||||
switch (mqnic->board_id) {
|
||||
case MQNIC_BOARD_ID_EXANIC_X10:
|
||||
case MQNIC_BOARD_ID_EXANIC_X25:
|
||||
case MQNIC_BOARD_ID_ADM_PCIE_9V3:
|
||||
|
||||
// create I2C adapter
|
||||
adapter = mqnic_create_i2c_adapter(mqnic, mqnic->hw_addr+MQNIC_REG_GPIO_I2C_1);
|
||||
|
||||
// I2C EEPROM
|
||||
mqnic->eeprom_i2c_client = create_i2c_client(adapter, "24c02", 0x50, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Read MAC from EEPROM
|
||||
if (mqnic->eeprom_i2c_client)
|
||||
{
|
||||
int r, k;
|
||||
|
||||
r = i2c_smbus_read_i2c_block_data(mqnic->eeprom_i2c_client, 0x00, 6, mqnic->mac_list[0]);
|
||||
if (r < 0)
|
||||
{
|
||||
dev_warn(mqnic->dev, "Failed to read MAC from EEPROM");
|
||||
}
|
||||
else
|
||||
{
|
||||
mqnic->mac_count = MQNIC_MAX_IF;
|
||||
for (k = 1; k < mqnic->mac_count; k++)
|
||||
{
|
||||
memcpy(mqnic->mac_list[k], mqnic->mac_list[0], ETH_ALEN);
|
||||
mqnic->mac_list[k][ETH_ALEN-1] += k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return &bus->adapter;
|
||||
}
|
||||
|
||||
void mqnic_remove_i2c(struct mqnic_dev *mqnic)
|
||||
void mqnic_i2c_bus_release(struct mqnic_i2c_bus *bus)
|
||||
{
|
||||
int k;
|
||||
struct mqnic_dev *mqnic;
|
||||
|
||||
// unregister I2C clients
|
||||
for (k = 0; k < ARRAY_SIZE(mqnic->mod_i2c_client); k++)
|
||||
{
|
||||
if (mqnic->mod_i2c_client[k])
|
||||
{
|
||||
i2c_unregister_device(mqnic->mod_i2c_client[k]);
|
||||
mqnic->mod_i2c_client[k] = NULL;
|
||||
}
|
||||
}
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
if (mqnic->eeprom_i2c_client)
|
||||
{
|
||||
i2c_unregister_device(mqnic->eeprom_i2c_client);
|
||||
mqnic->eeprom_i2c_client = NULL;
|
||||
}
|
||||
mqnic = bus->mqnic;
|
||||
|
||||
// delete adapters
|
||||
for (k = 0; k < ARRAY_SIZE(mqnic->i2c_adapter); k++)
|
||||
{
|
||||
if (mqnic->i2c_adapter[k].owner)
|
||||
{
|
||||
i2c_del_adapter(&mqnic->i2c_adapter[k]);
|
||||
}
|
||||
mqnic->i2c_adapter_count--;
|
||||
|
||||
memset(&mqnic->i2c_adapter[k], 0, sizeof(mqnic->i2c_adapter[k]));
|
||||
}
|
||||
i2c_del_adapter(&bus->adapter);
|
||||
list_del(&bus->head);
|
||||
kfree(bus);
|
||||
}
|
||||
|
||||
void mqnic_i2c_adapter_release(struct i2c_adapter *adapter)
|
||||
{
|
||||
struct mqnic_i2c_bus *bus;
|
||||
|
||||
if (!adapter)
|
||||
return;
|
||||
|
||||
bus = container_of(adapter, struct mqnic_i2c_bus, adapter);
|
||||
mqnic_i2c_bus_release(bus);
|
||||
}
|
||||
|
||||
int mqnic_i2c_init(struct mqnic_dev *mqnic)
|
||||
{
|
||||
INIT_LIST_HEAD(&mqnic->i2c_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mqnic_i2c_deinit(struct mqnic_dev *mqnic)
|
||||
{
|
||||
while (!list_empty(&mqnic->i2c_bus))
|
||||
{
|
||||
struct mqnic_i2c_bus *bus = list_first_entry(&mqnic->i2c_bus, typeof(*bus), head);
|
||||
mqnic_i2c_bus_release(bus);
|
||||
}
|
||||
}
|
||||
|
@ -250,12 +250,12 @@ static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent
|
||||
mqnic->irq_map[k] = pci_irq_vector(pdev, k);
|
||||
}
|
||||
|
||||
// Set up I2C interfaces
|
||||
ret = mqnic_init_i2c(mqnic);
|
||||
// Board-specific init
|
||||
ret = mqnic_board_init(mqnic);
|
||||
if (ret)
|
||||
{
|
||||
dev_err(dev, "Failed to register I2C interfaces");
|
||||
goto fail_i2c;
|
||||
dev_err(dev, "Failed to initialize board");
|
||||
goto fail_board;
|
||||
}
|
||||
|
||||
// Enable bus mastering for DMA
|
||||
@ -320,8 +320,8 @@ fail_init_netdev:
|
||||
}
|
||||
mqnic_unregister_phc(mqnic);
|
||||
pci_clear_master(pdev);
|
||||
fail_i2c:
|
||||
mqnic_remove_i2c(mqnic);
|
||||
fail_board:
|
||||
mqnic_board_deinit(mqnic);
|
||||
for (k = 0; k < mqnic->irq_count; k++)
|
||||
{
|
||||
pci_free_irq(pdev, k, mqnic);
|
||||
@ -365,7 +365,7 @@ static void mqnic_pci_remove(struct pci_dev *pdev)
|
||||
mqnic_unregister_phc(mqnic);
|
||||
|
||||
pci_clear_master(pdev);
|
||||
mqnic_remove_i2c(mqnic);
|
||||
mqnic_board_deinit(mqnic);
|
||||
for (k = 0; k < mqnic->irq_count; k++)
|
||||
{
|
||||
pci_free_irq(pdev, k, mqnic);
|
||||
|
Loading…
x
Reference in New Issue
Block a user