Commit 36195d86 authored by David S. Miller's avatar David S. Miller

Merge branch 'liquidio-next'

Raghu Vatsavayi says:

====================
liquidio: updates and bug fixes

Please consider following patch series for liquidio bug fixes
and updates on top of net-next. Following patches should be
applied in the following order as some of them depend on
earlier patches in the series.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b38066da 4b129ae3
...@@ -367,7 +367,8 @@ void lio_cn6xxx_enable_io_queues(struct octeon_device *oct) ...@@ -367,7 +367,8 @@ void lio_cn6xxx_enable_io_queues(struct octeon_device *oct)
void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
{ {
u32 mask, i, loop = HZ; int i;
u32 mask, loop = HZ;
u32 d32; u32 d32;
/* Reset the Enable bits for Input Queues. */ /* Reset the Enable bits for Input Queues. */
...@@ -376,7 +377,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) ...@@ -376,7 +377,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask); octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, mask);
/* Wait until hardware indicates that the queues are out of reset. */ /* Wait until hardware indicates that the queues are out of reset. */
mask = oct->io_qmask.iq; mask = (u32)oct->io_qmask.iq;
d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ); d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
while (((d32 & mask) != mask) && loop--) { while (((d32 & mask) != mask) && loop--) {
d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ); d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_IQ);
...@@ -384,8 +385,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) ...@@ -384,8 +385,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
} }
/* Reset the doorbell register for each Input queue. */ /* Reset the doorbell register for each Input queue. */
for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
if (!(oct->io_qmask.iq & (1UL << i))) if (!(oct->io_qmask.iq & (1ULL << i)))
continue; continue;
octeon_write_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i), 0xFFFFFFFF); octeon_write_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i), 0xFFFFFFFF);
d32 = octeon_read_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i)); d32 = octeon_read_csr(oct, CN6XXX_SLI_IQ_DOORBELL(i));
...@@ -398,7 +399,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) ...@@ -398,7 +399,7 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
/* Wait until hardware indicates that the queues are out of reset. */ /* Wait until hardware indicates that the queues are out of reset. */
loop = HZ; loop = HZ;
mask = oct->io_qmask.oq; mask = (u32)oct->io_qmask.oq;
d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ); d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
while (((d32 & mask) != mask) && loop--) { while (((d32 & mask) != mask) && loop--) {
d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ); d32 = octeon_read_csr(oct, CN6XXX_SLI_PORT_IN_RST_OQ);
...@@ -408,8 +409,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) ...@@ -408,8 +409,8 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
/* Reset the doorbell register for each Output queue. */ /* Reset the doorbell register for each Output queue. */
/* for (i = 0; i < oct->num_oqs; i++) { */ /* for (i = 0; i < oct->num_oqs; i++) { */
for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
if (!(oct->io_qmask.oq & (1UL << i))) if (!(oct->io_qmask.oq & (1ULL << i)))
continue; continue;
octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i), 0xFFFFFFFF); octeon_write_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i), 0xFFFFFFFF);
d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i)); d32 = octeon_read_csr(oct, CN6XXX_SLI_OQ_PKTS_CREDIT(i));
...@@ -429,16 +430,16 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct) ...@@ -429,16 +430,16 @@ void lio_cn6xxx_disable_io_queues(struct octeon_device *oct)
void lio_cn6xxx_reinit_regs(struct octeon_device *oct) void lio_cn6xxx_reinit_regs(struct octeon_device *oct)
{ {
u32 i; int i;
for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
if (!(oct->io_qmask.iq & (1UL << i))) if (!(oct->io_qmask.iq & (1ULL << i)))
continue; continue;
oct->fn_list.setup_iq_regs(oct, i); oct->fn_list.setup_iq_regs(oct, i);
} }
for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
if (!(oct->io_qmask.oq & (1UL << i))) if (!(oct->io_qmask.oq & (1ULL << i)))
continue; continue;
oct->fn_list.setup_oq_regs(oct, i); oct->fn_list.setup_oq_regs(oct, i);
} }
...@@ -450,8 +451,8 @@ void lio_cn6xxx_reinit_regs(struct octeon_device *oct) ...@@ -450,8 +451,8 @@ void lio_cn6xxx_reinit_regs(struct octeon_device *oct)
oct->fn_list.enable_io_queues(oct); oct->fn_list.enable_io_queues(oct);
/* for (i = 0; i < oct->num_oqs; i++) { */ /* for (i = 0; i < oct->num_oqs; i++) { */
for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
if (!(oct->io_qmask.oq & (1UL << i))) if (!(oct->io_qmask.oq & (1ULL << i)))
continue; continue;
writel(oct->droq[i]->max_count, oct->droq[i]->pkts_credit_reg); writel(oct->droq[i]->max_count, oct->droq[i]->pkts_credit_reg);
} }
...@@ -495,8 +496,7 @@ u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx) ...@@ -495,8 +496,7 @@ u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx)
} }
u32 u32
lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)), lio_cn6xxx_update_read_index(struct octeon_instr_queue *iq)
struct octeon_instr_queue *iq)
{ {
u32 new_idx = readl(iq->inst_cnt_reg); u32 new_idx = readl(iq->inst_cnt_reg);
...@@ -557,7 +557,8 @@ lio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64) ...@@ -557,7 +557,8 @@ lio_cn6xxx_process_pcie_error_intr(struct octeon_device *oct, u64 intr64)
int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct) int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct)
{ {
struct octeon_droq *droq; struct octeon_droq *droq;
u32 oq_no, pkt_count, droq_time_mask, droq_mask, droq_int_enb; int oq_no;
u32 pkt_count, droq_time_mask, droq_mask, droq_int_enb;
u32 droq_cnt_enb, droq_cnt_mask; u32 droq_cnt_enb, droq_cnt_mask;
droq_cnt_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB); droq_cnt_enb = octeon_read_csr(oct, CN6XXX_SLI_PKT_CNT_INT_ENB);
...@@ -573,8 +574,8 @@ int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct) ...@@ -573,8 +574,8 @@ int lio_cn6xxx_process_droq_intr_regs(struct octeon_device *oct)
oct->droq_intr = 0; oct->droq_intr = 0;
/* for (oq_no = 0; oq_no < oct->num_oqs; oq_no++) { */ /* for (oq_no = 0; oq_no < oct->num_oqs; oq_no++) { */
for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES; oq_no++) { for (oq_no = 0; oq_no < MAX_OCTEON_OUTPUT_QUEUES(oct); oq_no++) {
if (!(droq_mask & (1 << oq_no))) if (!(droq_mask & (1ULL << oq_no)))
continue; continue;
droq = oct->droq[oq_no]; droq = oct->droq[oq_no];
......
...@@ -91,8 +91,7 @@ void lio_cn6xxx_bar1_idx_setup(struct octeon_device *oct, u64 core_addr, ...@@ -91,8 +91,7 @@ void lio_cn6xxx_bar1_idx_setup(struct octeon_device *oct, u64 core_addr,
void lio_cn6xxx_bar1_idx_write(struct octeon_device *oct, u32 idx, u32 mask); void lio_cn6xxx_bar1_idx_write(struct octeon_device *oct, u32 idx, u32 mask);
u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx); u32 lio_cn6xxx_bar1_idx_read(struct octeon_device *oct, u32 idx);
u32 u32
lio_cn6xxx_update_read_index(struct octeon_device *oct __attribute__((unused)), lio_cn6xxx_update_read_index(struct octeon_instr_queue *iq);
struct octeon_instr_queue *iq);
void lio_cn6xxx_enable_interrupt(void *chip); void lio_cn6xxx_enable_interrupt(void *chip);
void lio_cn6xxx_disable_interrupt(void *chip); void lio_cn6xxx_disable_interrupt(void *chip);
void cn6xxx_get_pcie_qlmport(struct octeon_device *oct); void cn6xxx_get_pcie_qlmport(struct octeon_device *oct);
......
...@@ -30,11 +30,10 @@ ...@@ -30,11 +30,10 @@
#include "octeon_config.h" #include "octeon_config.h"
#define LIQUIDIO_VERSION "1.1.9" #define LIQUIDIO_BASE_VERSION "1.4"
#define LIQUIDIO_MAJOR_VERSION 1 #define LIQUIDIO_MICRO_VERSION ".1"
#define LIQUIDIO_MINOR_VERSION 1 #define LIQUIDIO_PACKAGE ""
#define LIQUIDIO_MICRO_VERSION 9 #define LIQUIDIO_VERSION "1.4.1"
#define CONTROL_IQ 0 #define CONTROL_IQ 0
/** Tag types used by Octeon cores in its work. */ /** Tag types used by Octeon cores in its work. */
enum octeon_tag_type { enum octeon_tag_type {
...@@ -214,6 +213,10 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, ...@@ -214,6 +213,10 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
#define OCTNET_CMD_VERBOSE_ENABLE 0x14 #define OCTNET_CMD_VERBOSE_ENABLE 0x14
#define OCTNET_CMD_VERBOSE_DISABLE 0x15 #define OCTNET_CMD_VERBOSE_DISABLE 0x15
#define OCTNET_CMD_ENABLE_VLAN_FILTER 0x16
#define OCTNET_CMD_ADD_VLAN_FILTER 0x17
#define OCTNET_CMD_DEL_VLAN_FILTER 0x18
/* RX(packets coming from wire) Checksum verification flags */ /* RX(packets coming from wire) Checksum verification flags */
/* TCP/UDP csum */ /* TCP/UDP csum */
#define CNNIC_L4SUM_VERIFIED 0x1 #define CNNIC_L4SUM_VERIFIED 0x1
...@@ -482,15 +485,15 @@ struct octeon_instr_irh { ...@@ -482,15 +485,15 @@ struct octeon_instr_irh {
u64 opcode:4; u64 opcode:4;
u64 rflag:1; u64 rflag:1;
u64 subcode:7; u64 subcode:7;
u64 len:3; u64 vlan:12;
u64 rid:13; u64 priority:3;
u64 reserved:4; u64 reserved:5;
u64 ossp:32; /* opcode/subcode specific parameters */ u64 ossp:32; /* opcode/subcode specific parameters */
#else #else
u64 ossp:32; /* opcode/subcode specific parameters */ u64 ossp:32; /* opcode/subcode specific parameters */
u64 reserved:4; u64 reserved:5;
u64 rid:13; u64 priority:3;
u64 len:3; u64 vlan:12;
u64 subcode:7; u64 subcode:7;
u64 rflag:1; u64 rflag:1;
u64 opcode:4; u64 opcode:4;
...@@ -517,28 +520,27 @@ union octeon_rh { ...@@ -517,28 +520,27 @@ union octeon_rh {
struct { struct {
u64 opcode:4; u64 opcode:4;
u64 subcode:8; u64 subcode:8;
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 rid:13; /** request id in response to pkt sent by host */ u64 reserved:17;
u64 reserved:4; u64 ossp:32; /** opcode/subcode specific parameters */
u64 ossp:32; /** opcode/subcode specific parameters */
} r; } r;
struct { struct {
u64 opcode:4; u64 opcode:4;
u64 subcode:8; u64 subcode:8;
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 rid:13; /** request id in response to pkt sent by host */ u64 extra:28;
u64 extra:24; u64 vlan:12;
u64 link:8; u64 priority:3;
u64 csum_verified:3; /** checksum verified. */ u64 csum_verified:3; /** checksum verified. */
u64 has_hwtstamp:1; /** Has hardware timestamp. 1 = yes. */ u64 has_hwtstamp:1; /** Has hardware timestamp. 1 = yes. */
} r_dh; } r_dh;
struct { struct {
u64 opcode:4; u64 opcode:4;
u64 subcode:8; u64 subcode:8;
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 rid:13; /** request id in response to pkt sent by host */ u64 reserved:11;
u64 num_gmx_ports:8; u64 num_gmx_ports:8;
u64 max_nic_ports:8; u64 max_nic_ports:10;
u64 app_cap_flags:4; u64 app_cap_flags:4;
u64 app_mode:16; u64 app_mode:16;
} r_core_drv_init; } r_core_drv_init;
...@@ -554,8 +556,7 @@ union octeon_rh { ...@@ -554,8 +556,7 @@ union octeon_rh {
u64 u64; u64 u64;
struct { struct {
u64 ossp:32; /** opcode/subcode specific parameters */ u64 ossp:32; /** opcode/subcode specific parameters */
u64 reserved:4; u64 reserved:17;
u64 rid:13; /** req id in response to pkt sent by host */
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 subcode:8; u64 subcode:8;
u64 opcode:4; u64 opcode:4;
...@@ -563,9 +564,9 @@ union octeon_rh { ...@@ -563,9 +564,9 @@ union octeon_rh {
struct { struct {
u64 has_hwtstamp:1; /** 1 = has hwtstamp */ u64 has_hwtstamp:1; /** 1 = has hwtstamp */
u64 csum_verified:3; /** checksum verified. */ u64 csum_verified:3; /** checksum verified. */
u64 link:8; u64 priority:3;
u64 extra:24; u64 vlan:12;
u64 rid:13; /** req id in response to pkt sent by host */ u64 extra:28;
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 subcode:8; u64 subcode:8;
u64 opcode:4; u64 opcode:4;
...@@ -573,9 +574,9 @@ union octeon_rh { ...@@ -573,9 +574,9 @@ union octeon_rh {
struct { struct {
u64 app_mode:16; u64 app_mode:16;
u64 app_cap_flags:4; u64 app_cap_flags:4;
u64 max_nic_ports:8; u64 max_nic_ports:10;
u64 num_gmx_ports:8; u64 num_gmx_ports:8;
u64 rid:13; u64 reserved:11;
u64 len:3; /** additional 64-bit words */ u64 len:3; /** additional 64-bit words */
u64 subcode:8; u64 subcode:8;
u64 opcode:4; u64 opcode:4;
...@@ -627,13 +628,13 @@ union oct_link_status { ...@@ -627,13 +628,13 @@ union oct_link_status {
u64 speed:16; u64 speed:16;
u64 link_up:1; u64 link_up:1;
u64 autoneg:1; u64 autoneg:1;
u64 interface:4; u64 if_mode:5;
u64 pause:1; u64 pause:1;
u64 reserved:17; u64 reserved:16;
#else #else
u64 reserved:17; u64 reserved:16;
u64 pause:1; u64 pause:1;
u64 interface:4; u64 if_mode:5;
u64 autoneg:1; u64 autoneg:1;
u64 link_up:1; u64 link_up:1;
u64 speed:16; u64 speed:16;
...@@ -710,6 +711,7 @@ struct liquidio_if_cfg_info { ...@@ -710,6 +711,7 @@ struct liquidio_if_cfg_info {
u64 iqmask; /** mask for IQs enabled for the port */ u64 iqmask; /** mask for IQs enabled for the port */
u64 oqmask; /** mask for OQs enabled for the port */ u64 oqmask; /** mask for OQs enabled for the port */
struct oct_link_info linfo; /** initial link information */ struct oct_link_info linfo; /** initial link information */
char liquidio_firmware_version[32];
}; };
/** Stats for each NIC port in RX direction. */ /** Stats for each NIC port in RX direction. */
...@@ -734,10 +736,16 @@ struct nic_rx_stats { ...@@ -734,10 +736,16 @@ struct nic_rx_stats {
u64 fw_err_pko; u64 fw_err_pko;
u64 fw_err_link; u64 fw_err_link;
u64 fw_err_drop; u64 fw_err_drop;
/* LRO */
u64 fw_lro_pkts; /* Number of packets that are LROed */ u64 fw_lro_pkts; /* Number of packets that are LROed */
u64 fw_lro_octs; /* Number of octets that are LROed */ u64 fw_lro_octs; /* Number of octets that are LROed */
u64 fw_total_lro; /* Number of LRO packets formed */ u64 fw_total_lro; /* Number of LRO packets formed */
u64 fw_lro_aborts; /* Number of times lRO of packet aborted */ u64 fw_lro_aborts; /* Number of times lRO of packet aborted */
u64 fw_lro_aborts_port;
u64 fw_lro_aborts_seq;
u64 fw_lro_aborts_tsval;
u64 fw_lro_aborts_timer;
/* intrmod: packet forward rate */ /* intrmod: packet forward rate */
u64 fwd_rate; u64 fwd_rate;
}; };
...@@ -761,9 +769,13 @@ struct nic_tx_stats { ...@@ -761,9 +769,13 @@ struct nic_tx_stats {
/* firmware stats */ /* firmware stats */
u64 fw_total_sent; u64 fw_total_sent;
u64 fw_total_fwd; u64 fw_total_fwd;
u64 fw_total_fwd_bytes;
u64 fw_err_pko; u64 fw_err_pko;
u64 fw_err_link; u64 fw_err_link;
u64 fw_err_drop; u64 fw_err_drop;
u64 fw_err_tso;
u64 fw_tso; /* number of tso requests */
u64 fw_tso_fwd; /* number of packets segmented in tso */
}; };
struct oct_link_stats { struct oct_link_stats {
...@@ -794,23 +806,44 @@ struct oct_mdio_cmd { ...@@ -794,23 +806,44 @@ struct oct_mdio_cmd {
#define OCT_LINK_STATS_SIZE (sizeof(struct oct_link_stats)) #define OCT_LINK_STATS_SIZE (sizeof(struct oct_link_stats))
/* intrmod: max. packet rate threshold */
#define LIO_INTRMOD_MAXPKT_RATETHR 196608
/* intrmod: min. packet rate threshold */
#define LIO_INTRMOD_MINPKT_RATETHR 9216
/* intrmod: max. packets to trigger interrupt */
#define LIO_INTRMOD_RXMAXCNT_TRIGGER 384
/* intrmod: min. packets to trigger interrupt */
#define LIO_INTRMOD_RXMINCNT_TRIGGER 1
/* intrmod: max. time to trigger interrupt */
#define LIO_INTRMOD_RXMAXTMR_TRIGGER 128
/* 66xx:intrmod: min. time to trigger interrupt
* (value of 1 is optimum for TCP_RR)
*/
#define LIO_INTRMOD_RXMINTMR_TRIGGER 1
/* intrmod: max. packets to trigger interrupt */
#define LIO_INTRMOD_TXMAXCNT_TRIGGER 64
/* intrmod: min. packets to trigger interrupt */
#define LIO_INTRMOD_TXMINCNT_TRIGGER 0
/* intrmod: poll interval in seconds */
#define LIO_INTRMOD_CHECK_INTERVAL 1 #define LIO_INTRMOD_CHECK_INTERVAL 1
#define LIO_INTRMOD_MAXPKT_RATETHR 196608 /* max pkt rate threshold */
#define LIO_INTRMOD_MINPKT_RATETHR 9216 /* min pkt rate threshold */
#define LIO_INTRMOD_MAXCNT_TRIGGER 384 /* max pkts to trigger interrupt */
#define LIO_INTRMOD_MINCNT_TRIGGER 1 /* min pkts to trigger interrupt */
#define LIO_INTRMOD_MAXTMR_TRIGGER 128 /* max time to trigger interrupt */
#define LIO_INTRMOD_MINTMR_TRIGGER 32 /* min time to trigger interrupt */
struct oct_intrmod_cfg { struct oct_intrmod_cfg {
u64 intrmod_enable; u64 rx_enable;
u64 intrmod_check_intrvl; u64 tx_enable;
u64 intrmod_maxpkt_ratethr; u64 check_intrvl;
u64 intrmod_minpkt_ratethr; u64 maxpkt_ratethr;
u64 intrmod_maxcnt_trigger; u64 minpkt_ratethr;
u64 intrmod_maxtmr_trigger; u64 rx_maxcnt_trigger;
u64 intrmod_mincnt_trigger; u64 rx_mincnt_trigger;
u64 intrmod_mintmr_trigger; u64 rx_maxtmr_trigger;
u64 rx_mintmr_trigger;
u64 tx_mincnt_trigger;
u64 tx_maxcnt_trigger;
u64 rx_frames;
u64 tx_frames;
u64 rx_usecs;
}; };
#define BASE_QUEUE_NOT_REQUESTED 65535 #define BASE_QUEUE_NOT_REQUESTED 65535
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
/* Maximum octeon devices defined as MAX_OCTEON_NICIF to support /* Maximum octeon devices defined as MAX_OCTEON_NICIF to support
* multiple(<= MAX_OCTEON_NICIF) Miniports * multiple(<= MAX_OCTEON_NICIF) Miniports
*/ */
#define MAX_OCTEON_NICIF 32 #define MAX_OCTEON_NICIF 128
#define MAX_OCTEON_DEVICES MAX_OCTEON_NICIF #define MAX_OCTEON_DEVICES MAX_OCTEON_NICIF
#define MAX_OCTEON_LINKS MAX_OCTEON_NICIF #define MAX_OCTEON_LINKS MAX_OCTEON_NICIF
#define MAX_OCTEON_MULTICAST_ADDR 32 #define MAX_OCTEON_MULTICAST_ADDR 32
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
#define CFG_GET_IS_SLI_BP_ON(cfg) ((cfg)->misc.enable_sli_oq_bp) #define CFG_GET_IS_SLI_BP_ON(cfg) ((cfg)->misc.enable_sli_oq_bp)
/* Max IOQs per OCTEON Link */ /* Max IOQs per OCTEON Link */
#define MAX_IOQS_PER_NICIF 32 #define MAX_IOQS_PER_NICIF 64
enum lio_card_type { enum lio_card_type {
LIO_210SV = 0, /* Two port, 66xx */ LIO_210SV = 0, /* Two port, 66xx */
...@@ -416,9 +416,11 @@ struct octeon_config { ...@@ -416,9 +416,11 @@ struct octeon_config {
#define DISPATCH_LIST_SIZE BIT(OPCODE_MASK_BITS) #define DISPATCH_LIST_SIZE BIT(OPCODE_MASK_BITS)
/* Maximum number of Octeon Instruction (command) queues */ /* Maximum number of Octeon Instruction (command) queues */
#define MAX_OCTEON_INSTR_QUEUES CN6XXX_MAX_INPUT_QUEUES #define MAX_OCTEON_INSTR_QUEUES(oct) CN6XXX_MAX_INPUT_QUEUES
/* Maximum number of Octeon Output queues */
#define MAX_OCTEON_OUTPUT_QUEUES(oct) CN6XXX_MAX_OUTPUT_QUEUES
/* Maximum number of Octeon Instruction (command) queues */ #define MAX_POSSIBLE_OCTEON_INSTR_QUEUES CN6XXX_MAX_INPUT_QUEUES
#define MAX_OCTEON_OUTPUT_QUEUES CN6XXX_MAX_OUTPUT_QUEUES #define MAX_POSSIBLE_OCTEON_OUTPUT_QUEUES CN6XXX_MAX_OUTPUT_QUEUES
#endif /* __OCTEON_CONFIG_H__ */ #endif /* __OCTEON_CONFIG_H__ */
...@@ -549,17 +549,19 @@ static char *get_oct_app_string(u32 app_mode) ...@@ -549,17 +549,19 @@ static char *get_oct_app_string(u32 app_mode)
return oct_dev_app_str[CVM_DRV_INVALID_APP - CVM_DRV_APP_START]; return oct_dev_app_str[CVM_DRV_INVALID_APP - CVM_DRV_APP_START];
} }
u8 fbuf[4 * 1024 * 1024];
int octeon_download_firmware(struct octeon_device *oct, const u8 *data, int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
size_t size) size_t size)
{ {
int ret = 0; int ret = 0;
u8 *p; u8 *p = fbuf;
u8 *buffer;
u32 crc32_result; u32 crc32_result;
u64 load_addr; u64 load_addr;
u32 image_len; u32 image_len;
struct octeon_firmware_file_header *h; struct octeon_firmware_file_header *h;
u32 i; u32 i, rem, base_len = strlen(LIQUIDIO_BASE_VERSION);
char *base;
if (size < sizeof(struct octeon_firmware_file_header)) { if (size < sizeof(struct octeon_firmware_file_header)) {
dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n", dev_err(&oct->pci_dev->dev, "Firmware file too small (%d < %d).\n",
...@@ -575,19 +577,26 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data, ...@@ -575,19 +577,26 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
return -EINVAL; return -EINVAL;
} }
crc32_result = crc32_result = crc32((unsigned int)~0, data,
crc32(~0, data, sizeof(struct octeon_firmware_file_header) -
sizeof(struct octeon_firmware_file_header) - sizeof(u32)) ^ ~0U;
sizeof(u32)) ^ ~0U;
if (crc32_result != be32_to_cpu(h->crc32)) { if (crc32_result != be32_to_cpu(h->crc32)) {
dev_err(&oct->pci_dev->dev, "Firmware CRC mismatch (0x%08x != 0x%08x).\n", dev_err(&oct->pci_dev->dev, "Firmware CRC mismatch (0x%08x != 0x%08x).\n",
crc32_result, be32_to_cpu(h->crc32)); crc32_result, be32_to_cpu(h->crc32));
return -EINVAL; return -EINVAL;
} }
if (memcmp(LIQUIDIO_VERSION, h->version, strlen(LIQUIDIO_VERSION))) { if (strncmp(LIQUIDIO_PACKAGE, h->version, strlen(LIQUIDIO_PACKAGE))) {
dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s, got %s.\n", dev_err(&oct->pci_dev->dev, "Unmatched firmware package type. Expected %s, got %s.\n",
LIQUIDIO_VERSION, h->version); LIQUIDIO_PACKAGE, h->version);
return -EINVAL;
}
base = h->version + strlen(LIQUIDIO_PACKAGE);
ret = memcmp(LIQUIDIO_BASE_VERSION, base, base_len);
if (ret) {
dev_err(&oct->pci_dev->dev, "Unmatched firmware version. Expected %s.x, got %s.\n",
LIQUIDIO_BASE_VERSION, base);
return -EINVAL; return -EINVAL;
} }
...@@ -601,56 +610,56 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data, ...@@ -601,56 +610,56 @@ int octeon_download_firmware(struct octeon_device *oct, const u8 *data,
snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s", snprintf(oct->fw_info.liquidio_firmware_version, 32, "LIQUIDIO: %s",
h->version); h->version);
buffer = kmemdup(data, size, GFP_KERNEL); data += sizeof(struct octeon_firmware_file_header);
if (!buffer)
return -ENOMEM;
p = buffer + sizeof(struct octeon_firmware_file_header);
dev_info(&oct->pci_dev->dev, "%s: Loading %d images\n", __func__,
be32_to_cpu(h->num_images));
/* load all images */ /* load all images */
for (i = 0; i < be32_to_cpu(h->num_images); i++) { for (i = 0; i < be32_to_cpu(h->num_images); i++) {
load_addr = be64_to_cpu(h->desc[i].addr); load_addr = be64_to_cpu(h->desc[i].addr);
image_len = be32_to_cpu(h->desc[i].len); image_len = be32_to_cpu(h->desc[i].len);
/* validate the image */ dev_info(&oct->pci_dev->dev, "Loading firmware %d at %llx\n",
crc32_result = crc32(~0, p, image_len) ^ ~0U; image_len, load_addr);
if (crc32_result != be32_to_cpu(h->desc[i].crc32)) {
dev_err(&oct->pci_dev->dev,
"Firmware CRC mismatch in image %d (0x%08x != 0x%08x).\n",
i, crc32_result,
be32_to_cpu(h->desc[i].crc32));
ret = -EINVAL;
goto done_downloading;
}
/* download the image */ /* Write in 4MB chunks*/
octeon_pci_write_core_mem(oct, load_addr, p, image_len); rem = image_len;
p += image_len; while (rem) {
dev_dbg(&oct->pci_dev->dev, if (rem < (4 * 1024 * 1024))
"Downloaded image %d (%d bytes) to address 0x%016llx\n", size = rem;
i, image_len, load_addr); else
size = 4 * 1024 * 1024;
memcpy(p, data, size);
/* download the image */
octeon_pci_write_core_mem(oct, load_addr, p, (u32)size);
data += size;
rem -= (u32)size;
load_addr += size;
}
} }
dev_info(&oct->pci_dev->dev, "Writing boot command: %s\n",
h->bootcmd);
/* Invoke the bootcmd */ /* Invoke the bootcmd */
ret = octeon_console_send_cmd(oct, h->bootcmd, 50); ret = octeon_console_send_cmd(oct, h->bootcmd, 50);
done_downloading: return 0;
kfree(buffer);
return ret;
} }
void octeon_free_device_mem(struct octeon_device *oct) void octeon_free_device_mem(struct octeon_device *oct)
{ {
u32 i; u32 i;
for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
/* could check mask as well */ /* could check mask as well */
vfree(oct->droq[i]); vfree(oct->droq[i]);
} }
for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
/* could check mask as well */ /* could check mask as well */
vfree(oct->instr_queue[i]); vfree(oct->instr_queue[i]);
} }
...@@ -734,7 +743,7 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, ...@@ -734,7 +743,7 @@ struct octeon_device *octeon_allocate_device(u32 pci_id,
octeon_device[oct_idx] = oct; octeon_device[oct_idx] = oct;
oct->octeon_id = oct_idx; oct->octeon_id = oct_idx;
snprintf((oct->device_name), sizeof(oct->device_name), snprintf(oct->device_name, sizeof(oct->device_name),
"LiquidIO%d", (oct->octeon_id)); "LiquidIO%d", (oct->octeon_id));
return oct; return oct;
...@@ -1157,8 +1166,8 @@ int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf) ...@@ -1157,8 +1166,8 @@ int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf)
int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no)
{ {
if (oct && (q_no < MAX_OCTEON_INSTR_QUEUES) && if (oct && (q_no < MAX_OCTEON_INSTR_QUEUES(oct)) &&
(oct->io_qmask.iq & (1UL << q_no))) (oct->io_qmask.iq & (1ULL << q_no)))
return oct->instr_queue[q_no]->max_count; return oct->instr_queue[q_no]->max_count;
return -1; return -1;
...@@ -1166,8 +1175,8 @@ int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) ...@@ -1166,8 +1175,8 @@ int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no)
int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no) int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no)
{ {
if (oct && (q_no < MAX_OCTEON_OUTPUT_QUEUES) && if (oct && (q_no < MAX_OCTEON_OUTPUT_QUEUES(oct)) &&
(oct->io_qmask.oq & (1UL << q_no))) (oct->io_qmask.oq & (1ULL << q_no)))
return oct->droq[q_no]->max_count; return oct->droq[q_no]->max_count;
return -1; return -1;
} }
...@@ -1258,10 +1267,10 @@ void lio_pci_writeq(struct octeon_device *oct, ...@@ -1258,10 +1267,10 @@ void lio_pci_writeq(struct octeon_device *oct,
int octeon_mem_access_ok(struct octeon_device *oct) int octeon_mem_access_ok(struct octeon_device *oct)
{ {
u64 access_okay = 0; u64 access_okay = 0;
u64 lmc0_reset_ctl;
/* Check to make sure a DDR interface is enabled */ /* Check to make sure a DDR interface is enabled */
u64 lmc0_reset_ctl = lio_pci_readq(oct, CN6XXX_LMC0_RESET_CTL); lmc0_reset_ctl = lio_pci_readq(oct, CN6XXX_LMC0_RESET_CTL);
access_okay = (lmc0_reset_ctl & CN6XXX_LMC0_RESET_CTL_DDR3RST_MASK); access_okay = (lmc0_reset_ctl & CN6XXX_LMC0_RESET_CTL_DDR3RST_MASK);
return access_okay ? 0 : 1; return access_okay ? 0 : 1;
...@@ -1275,9 +1284,6 @@ int octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout) ...@@ -1275,9 +1284,6 @@ int octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout)
if (!timeout) if (!timeout)
return ret; return ret;
while (*timeout == 0)
schedule_timeout_uninterruptible(HZ / 10);
for (ms = 0; (ret != 0) && ((*timeout == 0) || (ms <= *timeout)); for (ms = 0; (ret != 0) && ((*timeout == 0) || (ms <= *timeout));
ms += HZ / 10) { ms += HZ / 10) {
ret = octeon_mem_access_ok(oct); ret = octeon_mem_access_ok(oct);
......
...@@ -152,9 +152,9 @@ struct octeon_mmio { ...@@ -152,9 +152,9 @@ struct octeon_mmio {
#define MAX_OCTEON_MAPS 32 #define MAX_OCTEON_MAPS 32
struct octeon_io_enable { struct octeon_io_enable {
u32 iq; u64 iq;
u32 oq; u64 oq;
u32 iq64B; u64 iq64B;
}; };
struct octeon_reg_list { struct octeon_reg_list {
...@@ -204,8 +204,7 @@ struct octeon_fn_list { ...@@ -204,8 +204,7 @@ struct octeon_fn_list {
void (*bar1_idx_setup)(struct octeon_device *, u64, u32, int); void (*bar1_idx_setup)(struct octeon_device *, u64, u32, int);
void (*bar1_idx_write)(struct octeon_device *, u32, u32); void (*bar1_idx_write)(struct octeon_device *, u32, u32);
u32 (*bar1_idx_read)(struct octeon_device *, u32); u32 (*bar1_idx_read)(struct octeon_device *, u32);
u32 (*update_iq_read_idx)(struct octeon_device *, u32 (*update_iq_read_idx)(struct octeon_instr_queue *);
struct octeon_instr_queue *);
void (*enable_oq_pkt_time_intr)(struct octeon_device *, u32); void (*enable_oq_pkt_time_intr)(struct octeon_device *, u32);
void (*disable_oq_pkt_time_intr)(struct octeon_device *, u32); void (*disable_oq_pkt_time_intr)(struct octeon_device *, u32);
...@@ -267,6 +266,7 @@ struct octdev_props { ...@@ -267,6 +266,7 @@ struct octdev_props {
/* Each interface in the Octeon device has a network /* Each interface in the Octeon device has a network
* device pointer (used for OS specific calls). * device pointer (used for OS specific calls).
*/ */
int napi_enabled;
int gmxport; int gmxport;
struct net_device *netdev; struct net_device *netdev;
}; };
...@@ -325,7 +325,8 @@ struct octeon_device { ...@@ -325,7 +325,8 @@ struct octeon_device {
struct octeon_sc_buffer_pool sc_buf_pool; struct octeon_sc_buffer_pool sc_buf_pool;
/** The input instruction queues */ /** The input instruction queues */
struct octeon_instr_queue *instr_queue[MAX_OCTEON_INSTR_QUEUES]; struct octeon_instr_queue *instr_queue
[MAX_POSSIBLE_OCTEON_INSTR_QUEUES];
/** The doubly-linked list of instruction response */ /** The doubly-linked list of instruction response */
struct octeon_response_list response_list[MAX_RESPONSE_LISTS]; struct octeon_response_list response_list[MAX_RESPONSE_LISTS];
...@@ -333,7 +334,7 @@ struct octeon_device { ...@@ -333,7 +334,7 @@ struct octeon_device {
u32 num_oqs; u32 num_oqs;
/** The DROQ output queues */ /** The DROQ output queues */
struct octeon_droq *droq[MAX_OCTEON_OUTPUT_QUEUES]; struct octeon_droq *droq[MAX_POSSIBLE_OCTEON_OUTPUT_QUEUES];
struct octeon_io_enable io_qmask; struct octeon_io_enable io_qmask;
...@@ -382,15 +383,29 @@ struct octeon_device { ...@@ -382,15 +383,29 @@ struct octeon_device {
struct cavium_wq dma_comp_wq; struct cavium_wq dma_comp_wq;
struct cavium_wq check_db_wq[MAX_OCTEON_INSTR_QUEUES]; /** Lock for dma response list */
spinlock_t cmd_resp_wqlock;
u32 cmd_resp_state;
struct cavium_wq check_db_wq[MAX_POSSIBLE_OCTEON_INSTR_QUEUES];
struct cavium_wk nic_poll_work; struct cavium_wk nic_poll_work;
struct cavium_wk console_poll_work[MAX_OCTEON_MAPS]; struct cavium_wk console_poll_work[MAX_OCTEON_MAPS];
void *priv; void *priv;
int rx_pause;
int tx_pause;
struct oct_link_stats link_stats; /*stastics from firmware*/
/* private flags to control driver-specific features through ethtool */
u32 priv_flags;
}; };
#define OCT_DRV_ONLINE 1
#define OCT_DRV_OFFLINE 2
#define OCTEON_CN6XXX(oct) ((oct->chip_id == OCTEON_CN66XX) || \ #define OCTEON_CN6XXX(oct) ((oct->chip_id == OCTEON_CN66XX) || \
(oct->chip_id == OCTEON_CN68XX)) (oct->chip_id == OCTEON_CN68XX))
#define CHIP_FIELD(oct, TYPE, field) \ #define CHIP_FIELD(oct, TYPE, field) \
...@@ -647,4 +662,17 @@ void *oct_get_config_info(struct octeon_device *oct, u16 card_type); ...@@ -647,4 +662,17 @@ void *oct_get_config_info(struct octeon_device *oct, u16 card_type);
*/ */
struct octeon_config *octeon_get_conf(struct octeon_device *oct); struct octeon_config *octeon_get_conf(struct octeon_device *oct);
/* LiquidIO driver pivate flags */
enum {
OCT_PRIV_FLAG_TX_BYTES = 0, /* Tx interrupts by pending byte count */
};
static inline void lio_set_priv_flag(struct octeon_device *octdev, u32 flag,
u32 val)
{
if (val)
octdev->priv_flags |= (0x1 << flag);
else
octdev->priv_flags &= ~(0x1 << flag);
}
#endif #endif
...@@ -337,7 +337,7 @@ int octeon_init_droq(struct octeon_device *oct, ...@@ -337,7 +337,7 @@ int octeon_init_droq(struct octeon_device *oct,
/* For 56xx Pass1, this function won't be called, so no checks. */ /* For 56xx Pass1, this function won't be called, so no checks. */
oct->fn_list.setup_oq_regs(oct, q_no); oct->fn_list.setup_oq_regs(oct, q_no);
oct->io_qmask.oq |= (1 << q_no); oct->io_qmask.oq |= (1ULL << q_no);
return 0; return 0;
......
...@@ -65,6 +65,10 @@ struct oct_iq_stats { ...@@ -65,6 +65,10 @@ struct oct_iq_stats {
u64 tx_iq_busy;/**< Numof times this iq was found to be full. */ u64 tx_iq_busy;/**< Numof times this iq was found to be full. */
u64 tx_dropped;/**< Numof pkts dropped dueto xmitpath errors. */ u64 tx_dropped;/**< Numof pkts dropped dueto xmitpath errors. */
u64 tx_tot_bytes;/**< Total count of bytes sento to network. */ u64 tx_tot_bytes;/**< Total count of bytes sento to network. */
u64 tx_gso; /* count of tso */
u64 tx_dmamap_fail;
u64 tx_restart;
/*u64 tx_timeout_count;*/
}; };
#define OCT_IQ_STATS_SIZE (sizeof(struct oct_iq_stats)) #define OCT_IQ_STATS_SIZE (sizeof(struct oct_iq_stats))
...@@ -80,6 +84,12 @@ struct octeon_instr_queue { ...@@ -80,6 +84,12 @@ struct octeon_instr_queue {
/** A spinlock to protect access to the input ring. */ /** A spinlock to protect access to the input ring. */
spinlock_t lock; spinlock_t lock;
/** A spinlock to protect while posting on the ring. */
spinlock_t post_lock;
/** A spinlock to protect access to the input ring.*/
spinlock_t iq_flush_running_lock;
/** Flag that indicates if the queue uses 64 byte commands. */ /** Flag that indicates if the queue uses 64 byte commands. */
u32 iqcmd_64B:1; u32 iqcmd_64B:1;
...@@ -244,7 +254,7 @@ union octeon_instr_64B { ...@@ -244,7 +254,7 @@ union octeon_instr_64B {
/** The size of each buffer in soft command buffer pool /** The size of each buffer in soft command buffer pool
*/ */
#define SOFT_COMMAND_BUFFER_SIZE 1024 #define SOFT_COMMAND_BUFFER_SIZE 1536
struct octeon_soft_command { struct octeon_soft_command {
/** Soft command buffer info. */ /** Soft command buffer info. */
...@@ -282,7 +292,7 @@ struct octeon_soft_command { ...@@ -282,7 +292,7 @@ struct octeon_soft_command {
/** Maximum number of buffers to allocate into soft command buffer pool /** Maximum number of buffers to allocate into soft command buffer pool
*/ */
#define MAX_SOFT_COMMAND_BUFFERS 16 #define MAX_SOFT_COMMAND_BUFFERS 256
/** Head of a soft command buffer pool. /** Head of a soft command buffer pool.
*/ */
...@@ -339,7 +349,7 @@ octeon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype, ...@@ -339,7 +349,7 @@ octeon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype,
int int
lio_process_iq_request_list(struct octeon_device *oct, lio_process_iq_request_list(struct octeon_device *oct,
struct octeon_instr_queue *iq); struct octeon_instr_queue *iq, u32 napi_budget);
int octeon_send_command(struct octeon_device *oct, u32 iq_no, int octeon_send_command(struct octeon_device *oct, u32 iq_no,
u32 force_db, void *cmd, void *buf, u32 force_db, void *cmd, void *buf,
...@@ -357,5 +367,7 @@ int octeon_send_soft_command(struct octeon_device *oct, ...@@ -357,5 +367,7 @@ int octeon_send_soft_command(struct octeon_device *oct,
int octeon_setup_iq(struct octeon_device *oct, int ifidx, int octeon_setup_iq(struct octeon_device *oct, int ifidx,
int q_index, union oct_txpciq iq_no, u32 num_descs, int q_index, union oct_txpciq iq_no, u32 num_descs,
void *app_ctx); void *app_ctx);
int
octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq,
u32 pending_thresh, u32 napi_budget);
#endif /* __OCTEON_IQ_H__ */ #endif /* __OCTEON_IQ_H__ */
...@@ -30,6 +30,17 @@ ...@@ -30,6 +30,17 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
struct oct_nic_stats_resp {
u64 rh;
struct oct_link_stats stats;
u64 status;
};
struct oct_nic_stats_ctrl {
struct completion complete;
struct net_device *netdev;
};
/** LiquidIO per-interface network private data */ /** LiquidIO per-interface network private data */
struct lio { struct lio {
/** State of the interface. Rx/Tx happens only in the RUNNING state. */ /** State of the interface. Rx/Tx happens only in the RUNNING state. */
......
...@@ -171,20 +171,36 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct, ...@@ -171,20 +171,36 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct,
int retval; int retval;
struct octeon_soft_command *sc = NULL; struct octeon_soft_command *sc = NULL;
spin_lock_bh(&oct->cmd_resp_wqlock);
/* Allow only rx ctrl command to stop traffic on the chip
* during offline operations
*/
if ((oct->cmd_resp_state == OCT_DRV_OFFLINE) &&
(nctrl->ncmd.s.cmd != OCTNET_CMD_RX_CTL)) {
spin_unlock_bh(&oct->cmd_resp_wqlock);
dev_err(&oct->pci_dev->dev,
"%s cmd:%d not processed since driver offline\n",
__func__, nctrl->ncmd.s.cmd);
return -1;
}
sc = octnic_alloc_ctrl_pkt_sc(oct, nctrl); sc = octnic_alloc_ctrl_pkt_sc(oct, nctrl);
if (!sc) { if (!sc) {
dev_err(&oct->pci_dev->dev, "%s soft command alloc failed\n", dev_err(&oct->pci_dev->dev, "%s soft command alloc failed\n",
__func__); __func__);
spin_unlock_bh(&oct->cmd_resp_wqlock);
return -1; return -1;
} }
retval = octeon_send_soft_command(oct, sc); retval = octeon_send_soft_command(oct, sc);
if (retval == IQ_SEND_FAILED) { if (retval == IQ_SEND_FAILED) {
octeon_free_soft_command(oct, sc); octeon_free_soft_command(oct, sc);
dev_err(&oct->pci_dev->dev, "%s soft command send failed status: %x\n", dev_err(&oct->pci_dev->dev, "%s soft command:%d send failed status: %x\n",
__func__, retval); __func__, nctrl->ncmd.s.cmd, retval);
spin_unlock_bh(&oct->cmd_resp_wqlock);
return -1; return -1;
} }
spin_unlock_bh(&oct->cmd_resp_wqlock);
return retval; return retval;
} }
...@@ -51,7 +51,7 @@ struct iq_post_status { ...@@ -51,7 +51,7 @@ struct iq_post_status {
}; };
static void check_db_timeout(struct work_struct *work); static void check_db_timeout(struct work_struct *work);
static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no); static void __check_db_timeout(struct octeon_device *oct, u64 iq_no);
static void (*reqtype_free_fn[MAX_OCTEON_DEVICES][REQTYPE_LAST + 1]) (void *); static void (*reqtype_free_fn[MAX_OCTEON_DEVICES][REQTYPE_LAST + 1]) (void *);
...@@ -149,8 +149,11 @@ int octeon_init_instr_queue(struct octeon_device *oct, ...@@ -149,8 +149,11 @@ int octeon_init_instr_queue(struct octeon_device *oct,
/* Initialize the spinlock for this instruction queue */ /* Initialize the spinlock for this instruction queue */
spin_lock_init(&iq->lock); spin_lock_init(&iq->lock);
spin_lock_init(&iq->post_lock);
oct->io_qmask.iq |= (1 << iq_no); spin_lock_init(&iq->iq_flush_running_lock);
oct->io_qmask.iq |= (1ULL << iq_no);
/* Set the 32B/64B mode for each input queue */ /* Set the 32B/64B mode for each input queue */
oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no); oct->io_qmask.iq64B |= ((conf->instr_type == 64) << iq_no);
...@@ -253,8 +256,8 @@ int lio_wait_for_instr_fetch(struct octeon_device *oct) ...@@ -253,8 +256,8 @@ int lio_wait_for_instr_fetch(struct octeon_device *oct)
instr_cnt = 0; instr_cnt = 0;
/*for (i = 0; i < oct->num_iqs; i++) {*/ /*for (i = 0; i < oct->num_iqs; i++) {*/
for (i = 0; i < MAX_OCTEON_INSTR_QUEUES; i++) { for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
if (!(oct->io_qmask.iq & (1UL << i))) if (!(oct->io_qmask.iq & (1ULL << i)))
continue; continue;
pending = pending =
atomic_read(&oct-> atomic_read(&oct->
...@@ -391,13 +394,13 @@ __add_to_request_list(struct octeon_instr_queue *iq, ...@@ -391,13 +394,13 @@ __add_to_request_list(struct octeon_instr_queue *iq,
int int
lio_process_iq_request_list(struct octeon_device *oct, lio_process_iq_request_list(struct octeon_device *oct,
struct octeon_instr_queue *iq) struct octeon_instr_queue *iq, u32 napi_budget)
{ {
int reqtype; int reqtype;
void *buf; void *buf;
u32 old = iq->flush_index; u32 old = iq->flush_index;
u32 inst_count = 0; u32 inst_count = 0;
unsigned pkts_compl = 0, bytes_compl = 0; unsigned int pkts_compl = 0, bytes_compl = 0;
struct octeon_soft_command *sc; struct octeon_soft_command *sc;
struct octeon_instr_irh *irh; struct octeon_instr_irh *irh;
...@@ -457,6 +460,9 @@ lio_process_iq_request_list(struct octeon_device *oct, ...@@ -457,6 +460,9 @@ lio_process_iq_request_list(struct octeon_device *oct,
skip_this: skip_this:
inst_count++; inst_count++;
INCR_INDEX_BY1(old, iq->max_count); INCR_INDEX_BY1(old, iq->max_count);
if ((napi_budget) && (inst_count >= napi_budget))
break;
} }
if (bytes_compl) if (bytes_compl)
octeon_report_tx_completion_to_bql(iq->app_ctx, pkts_compl, octeon_report_tx_completion_to_bql(iq->app_ctx, pkts_compl,
...@@ -466,38 +472,63 @@ lio_process_iq_request_list(struct octeon_device *oct, ...@@ -466,38 +472,63 @@ lio_process_iq_request_list(struct octeon_device *oct,
return inst_count; return inst_count;
} }
static inline void /* Can only be called from process context */
update_iq_indices(struct octeon_device *oct, struct octeon_instr_queue *iq) int
octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq,
u32 pending_thresh, u32 napi_budget)
{ {
u32 inst_processed = 0; u32 inst_processed = 0;
u32 tot_inst_processed = 0;
int tx_done = 1;
/* Calculate how many commands Octeon has read and move the read index if (!spin_trylock(&iq->iq_flush_running_lock))
* accordingly. return tx_done;
*/
iq->octeon_read_index = oct->fn_list.update_iq_read_idx(oct, iq);
/* Move the NORESPONSE requests to the per-device completion list. */ spin_lock_bh(&iq->lock);
if (iq->flush_index != iq->octeon_read_index)
inst_processed = lio_process_iq_request_list(oct, iq);
if (inst_processed) { iq->octeon_read_index = oct->fn_list.update_iq_read_idx(iq);
atomic_sub(inst_processed, &iq->instr_pending);
iq->stats.instr_processed += inst_processed;
}
}
static void
octeon_flush_iq(struct octeon_device *oct, struct octeon_instr_queue *iq,
u32 pending_thresh)
{
if (atomic_read(&iq->instr_pending) >= (s32)pending_thresh) { if (atomic_read(&iq->instr_pending) >= (s32)pending_thresh) {
spin_lock_bh(&iq->lock); do {
update_iq_indices(oct, iq); /* Process any outstanding IQ packets. */
spin_unlock_bh(&iq->lock); if (iq->flush_index == iq->octeon_read_index)
break;
if (napi_budget)
inst_processed = lio_process_iq_request_list
(oct, iq,
napi_budget - tot_inst_processed);
else
inst_processed =
lio_process_iq_request_list(oct, iq, 0);
if (inst_processed) {
atomic_sub(inst_processed, &iq->instr_pending);
iq->stats.instr_processed += inst_processed;
}
tot_inst_processed += inst_processed;
inst_processed = 0;
} while (tot_inst_processed < napi_budget);
if (napi_budget && (tot_inst_processed >= napi_budget))
tx_done = 0;
} }
iq->last_db_time = jiffies;
spin_unlock_bh(&iq->lock);
spin_unlock(&iq->iq_flush_running_lock);
return tx_done;
} }
static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no) /* Process instruction queue after timeout.
* This routine gets called from a workqueue or when removing the module.
*/
static void __check_db_timeout(struct octeon_device *oct, u64 iq_no)
{ {
struct octeon_instr_queue *iq; struct octeon_instr_queue *iq;
u64 next_time; u64 next_time;
...@@ -508,24 +539,17 @@ static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no) ...@@ -508,24 +539,17 @@ static void __check_db_timeout(struct octeon_device *oct, unsigned long iq_no)
if (!iq) if (!iq)
return; return;
/* return immediately, if no work pending */
if (!atomic_read(&iq->instr_pending))
return;
/* If jiffies - last_db_time < db_timeout do nothing */ /* If jiffies - last_db_time < db_timeout do nothing */
next_time = iq->last_db_time + iq->db_timeout; next_time = iq->last_db_time + iq->db_timeout;
if (!time_after(jiffies, (unsigned long)next_time)) if (!time_after(jiffies, (unsigned long)next_time))
return; return;
iq->last_db_time = jiffies; iq->last_db_time = jiffies;
/* Get the lock and prevent tasklets. This routine gets called from
* the poll thread. Instructions can now be posted in tasklet context
*/
spin_lock_bh(&iq->lock);
if (iq->fill_cnt != 0)
ring_doorbell(oct, iq);
spin_unlock_bh(&iq->lock);
/* Flush the instruction queue */ /* Flush the instruction queue */
if (iq->do_auto_flush) octeon_flush_iq(oct, iq, 1, 0);
octeon_flush_iq(oct, iq, 1);
} }
/* Called by the Poll thread at regular intervals to check the instruction /* Called by the Poll thread at regular intervals to check the instruction
...@@ -550,7 +574,10 @@ octeon_send_command(struct octeon_device *oct, u32 iq_no, ...@@ -550,7 +574,10 @@ octeon_send_command(struct octeon_device *oct, u32 iq_no,
struct iq_post_status st; struct iq_post_status st;
struct octeon_instr_queue *iq = oct->instr_queue[iq_no]; struct octeon_instr_queue *iq = oct->instr_queue[iq_no];
spin_lock_bh(&iq->lock); /* Get the lock and prevent other tasks and tx interrupt handler from
* running.
*/
spin_lock_bh(&iq->post_lock);
st = __post_command2(oct, iq, force_db, cmd); st = __post_command2(oct, iq, force_db, cmd);
...@@ -566,10 +593,13 @@ octeon_send_command(struct octeon_device *oct, u32 iq_no, ...@@ -566,10 +593,13 @@ octeon_send_command(struct octeon_device *oct, u32 iq_no,
INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_dropped, 1); INCR_INSTRQUEUE_PKT_COUNT(oct, iq_no, instr_dropped, 1);
} }
spin_unlock_bh(&iq->lock); spin_unlock_bh(&iq->post_lock);
if (iq->do_auto_flush) /* This is only done here to expedite packets being flushed
octeon_flush_iq(oct, iq, 2); * for cases where there are no IQ completion interrupts.
*/
/*if (iq->do_auto_flush)*/
/* octeon_flush_iq(oct, iq, 2, 0);*/
return st.status; return st.status;
} }
......
...@@ -54,6 +54,7 @@ int octeon_setup_response_list(struct octeon_device *oct) ...@@ -54,6 +54,7 @@ int octeon_setup_response_list(struct octeon_device *oct)
spin_lock_init(&oct->response_list[i].lock); spin_lock_init(&oct->response_list[i].lock);
atomic_set(&oct->response_list[i].pending_req_count, 0); atomic_set(&oct->response_list[i].pending_req_count, 0);
} }
spin_lock_init(&oct->cmd_resp_wqlock);
oct->dma_comp_wq.wq = alloc_workqueue("dma-comp", WQ_MEM_RECLAIM, 0); oct->dma_comp_wq.wq = alloc_workqueue("dma-comp", WQ_MEM_RECLAIM, 0);
if (!oct->dma_comp_wq.wq) { if (!oct->dma_comp_wq.wq) {
...@@ -64,6 +65,7 @@ int octeon_setup_response_list(struct octeon_device *oct) ...@@ -64,6 +65,7 @@ int octeon_setup_response_list(struct octeon_device *oct)
cwq = &oct->dma_comp_wq; cwq = &oct->dma_comp_wq;
INIT_DELAYED_WORK(&cwq->wk.work, oct_poll_req_completion); INIT_DELAYED_WORK(&cwq->wk.work, oct_poll_req_completion);
cwq->wk.ctxptr = oct; cwq->wk.ctxptr = oct;
oct->cmd_resp_state = OCT_DRV_ONLINE;
queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(100)); queue_delayed_work(cwq->wq, &cwq->wk.work, msecs_to_jiffies(100));
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment