162306a36Sopenharmony_ci/**********************************************************************
262306a36Sopenharmony_ci * Author: Cavium, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Contact: support@cavium.com
562306a36Sopenharmony_ci *          Please include "LiquidIO" in the subject.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2003-2016 Cavium, Inc.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is free software; you can redistribute it and/or modify
1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License, Version 2, as
1162306a36Sopenharmony_ci * published by the Free Software Foundation.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but
1462306a36Sopenharmony_ci * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
1562306a36Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
1662306a36Sopenharmony_ci * NONINFRINGEMENT.  See the GNU General Public License for more details.
1762306a36Sopenharmony_ci ***********************************************************************/
1862306a36Sopenharmony_ci#include <linux/pci.h>
1962306a36Sopenharmony_ci#include <linux/netdevice.h>
2062306a36Sopenharmony_ci#include <linux/vmalloc.h>
2162306a36Sopenharmony_ci#include "liquidio_common.h"
2262306a36Sopenharmony_ci#include "octeon_droq.h"
2362306a36Sopenharmony_ci#include "octeon_iq.h"
2462306a36Sopenharmony_ci#include "response_manager.h"
2562306a36Sopenharmony_ci#include "octeon_device.h"
2662306a36Sopenharmony_ci#include "octeon_main.h"
2762306a36Sopenharmony_ci#include "octeon_network.h"
2862306a36Sopenharmony_ci#include "cn66xx_regs.h"
2962306a36Sopenharmony_ci#include "cn66xx_device.h"
3062306a36Sopenharmony_ci#include "cn23xx_pf_device.h"
3162306a36Sopenharmony_ci#include "cn23xx_vf_device.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/** Default configuration
3462306a36Sopenharmony_ci *  for CN66XX OCTEON Models.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistatic struct octeon_config default_cn66xx_conf = {
3762306a36Sopenharmony_ci	.card_type                              = LIO_210SV,
3862306a36Sopenharmony_ci	.card_name                              = LIO_210SV_NAME,
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/** IQ attributes */
4162306a36Sopenharmony_ci	.iq					= {
4262306a36Sopenharmony_ci		.max_iqs			= CN6XXX_CFG_IO_QUEUES,
4362306a36Sopenharmony_ci		.pending_list_size		=
4462306a36Sopenharmony_ci			(CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
4562306a36Sopenharmony_ci		.instr_type			= OCTEON_64BYTE_INSTR,
4662306a36Sopenharmony_ci		.db_min				= CN6XXX_DB_MIN,
4762306a36Sopenharmony_ci		.db_timeout			= CN6XXX_DB_TIMEOUT,
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci	,
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/** OQ attributes */
5262306a36Sopenharmony_ci	.oq					= {
5362306a36Sopenharmony_ci		.max_oqs			= CN6XXX_CFG_IO_QUEUES,
5462306a36Sopenharmony_ci		.refill_threshold		= CN6XXX_OQ_REFIL_THRESHOLD,
5562306a36Sopenharmony_ci		.oq_intr_pkt			= CN6XXX_OQ_INTR_PKT,
5662306a36Sopenharmony_ci		.oq_intr_time			= CN6XXX_OQ_INTR_TIME,
5762306a36Sopenharmony_ci		.pkts_per_intr			= CN6XXX_OQ_PKTSPER_INTR,
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	,
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	.num_nic_ports				= DEFAULT_NUM_NIC_PORTS_66XX,
6262306a36Sopenharmony_ci	.num_def_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
6362306a36Sopenharmony_ci	.num_def_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
6462306a36Sopenharmony_ci	.def_rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* For ethernet interface 0:  Port cfg Attributes */
6762306a36Sopenharmony_ci	.nic_if_cfg[0] = {
6862306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
6962306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
7262306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
7562306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
7862306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		/* Num of desc for rx rings */
8162306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		/* Num of desc for tx rings */
8462306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
8762306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
8862306a36Sopenharmony_ci		 */
8962306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		.gmx_port_id			= 0,
9462306a36Sopenharmony_ci	},
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	.nic_if_cfg[1] = {
9762306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
9862306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
10162306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
10462306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
10762306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		/* Num of desc for rx rings */
11062306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		/* Num of desc for tx rings */
11362306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
11662306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
11762306a36Sopenharmony_ci		 */
11862306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		.gmx_port_id			= 1,
12362306a36Sopenharmony_ci	},
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/** Miscellaneous attributes */
12662306a36Sopenharmony_ci	.misc					= {
12762306a36Sopenharmony_ci		/* Host driver link query interval */
12862306a36Sopenharmony_ci		.oct_link_query_interval	= 100,
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		/* Octeon link query interval */
13162306a36Sopenharmony_ci		.host_link_query_interval	= 500,
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		.enable_sli_oq_bp		= 0,
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		/* Control queue group */
13662306a36Sopenharmony_ci		.ctrlq_grp			= 1,
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	,
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/** Default configuration
14262306a36Sopenharmony_ci *  for CN68XX OCTEON Model.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic struct octeon_config default_cn68xx_conf = {
14662306a36Sopenharmony_ci	.card_type                              = LIO_410NV,
14762306a36Sopenharmony_ci	.card_name                              = LIO_410NV_NAME,
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/** IQ attributes */
15062306a36Sopenharmony_ci	.iq					= {
15162306a36Sopenharmony_ci		.max_iqs			= CN6XXX_CFG_IO_QUEUES,
15262306a36Sopenharmony_ci		.pending_list_size		=
15362306a36Sopenharmony_ci			(CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
15462306a36Sopenharmony_ci		.instr_type			= OCTEON_64BYTE_INSTR,
15562306a36Sopenharmony_ci		.db_min				= CN6XXX_DB_MIN,
15662306a36Sopenharmony_ci		.db_timeout			= CN6XXX_DB_TIMEOUT,
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	,
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/** OQ attributes */
16162306a36Sopenharmony_ci	.oq					= {
16262306a36Sopenharmony_ci		.max_oqs			= CN6XXX_CFG_IO_QUEUES,
16362306a36Sopenharmony_ci		.refill_threshold		= CN6XXX_OQ_REFIL_THRESHOLD,
16462306a36Sopenharmony_ci		.oq_intr_pkt			= CN6XXX_OQ_INTR_PKT,
16562306a36Sopenharmony_ci		.oq_intr_time			= CN6XXX_OQ_INTR_TIME,
16662306a36Sopenharmony_ci		.pkts_per_intr			= CN6XXX_OQ_PKTSPER_INTR,
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	,
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	.num_nic_ports				= DEFAULT_NUM_NIC_PORTS_68XX,
17162306a36Sopenharmony_ci	.num_def_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
17262306a36Sopenharmony_ci	.num_def_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
17362306a36Sopenharmony_ci	.def_rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	.nic_if_cfg[0] = {
17662306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
17762306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
18062306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
18362306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
18662306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		/* Num of desc for rx rings */
18962306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		/* Num of desc for tx rings */
19262306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
19562306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
19662306a36Sopenharmony_ci		 */
19762306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		.gmx_port_id			= 0,
20262306a36Sopenharmony_ci	},
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	.nic_if_cfg[1] = {
20562306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
20662306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
20962306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
21262306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
21562306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		/* Num of desc for rx rings */
21862306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		/* Num of desc for tx rings */
22162306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
22462306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
22562306a36Sopenharmony_ci		 */
22662306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		.gmx_port_id			= 1,
23162306a36Sopenharmony_ci	},
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	.nic_if_cfg[2] = {
23462306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
23562306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
23862306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
24162306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
24462306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		/* Num of desc for rx rings */
24762306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		/* Num of desc for tx rings */
25062306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
25362306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
25462306a36Sopenharmony_ci		 */
25562306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		.gmx_port_id			= 2,
26062306a36Sopenharmony_ci	},
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	.nic_if_cfg[3] = {
26362306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
26462306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
26762306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
27062306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
27362306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		/* Num of desc for rx rings */
27662306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		/* Num of desc for tx rings */
27962306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
28262306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
28362306a36Sopenharmony_ci		 */
28462306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		.gmx_port_id			= 3,
28962306a36Sopenharmony_ci	},
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/** Miscellaneous attributes */
29262306a36Sopenharmony_ci	.misc					= {
29362306a36Sopenharmony_ci		/* Host driver link query interval */
29462306a36Sopenharmony_ci		.oct_link_query_interval	= 100,
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		/* Octeon link query interval */
29762306a36Sopenharmony_ci		.host_link_query_interval	= 500,
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		.enable_sli_oq_bp		= 0,
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		/* Control queue group */
30262306a36Sopenharmony_ci		.ctrlq_grp			= 1,
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	,
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/** Default configuration
30862306a36Sopenharmony_ci *  for CN68XX OCTEON Model.
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_cistatic struct octeon_config default_cn68xx_210nv_conf = {
31162306a36Sopenharmony_ci	.card_type                              = LIO_210NV,
31262306a36Sopenharmony_ci	.card_name                              = LIO_210NV_NAME,
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/** IQ attributes */
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	.iq					= {
31762306a36Sopenharmony_ci		.max_iqs			= CN6XXX_CFG_IO_QUEUES,
31862306a36Sopenharmony_ci		.pending_list_size		=
31962306a36Sopenharmony_ci			(CN6XXX_MAX_IQ_DESCRIPTORS * CN6XXX_CFG_IO_QUEUES),
32062306a36Sopenharmony_ci		.instr_type			= OCTEON_64BYTE_INSTR,
32162306a36Sopenharmony_ci		.db_min				= CN6XXX_DB_MIN,
32262306a36Sopenharmony_ci		.db_timeout			= CN6XXX_DB_TIMEOUT,
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	,
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/** OQ attributes */
32762306a36Sopenharmony_ci	.oq					= {
32862306a36Sopenharmony_ci		.max_oqs			= CN6XXX_CFG_IO_QUEUES,
32962306a36Sopenharmony_ci		.refill_threshold		= CN6XXX_OQ_REFIL_THRESHOLD,
33062306a36Sopenharmony_ci		.oq_intr_pkt			= CN6XXX_OQ_INTR_PKT,
33162306a36Sopenharmony_ci		.oq_intr_time			= CN6XXX_OQ_INTR_TIME,
33262306a36Sopenharmony_ci		.pkts_per_intr			= CN6XXX_OQ_PKTSPER_INTR,
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	,
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	.num_nic_ports			= DEFAULT_NUM_NIC_PORTS_68XX_210NV,
33762306a36Sopenharmony_ci	.num_def_rx_descs		= CN6XXX_MAX_OQ_DESCRIPTORS,
33862306a36Sopenharmony_ci	.num_def_tx_descs		= CN6XXX_MAX_IQ_DESCRIPTORS,
33962306a36Sopenharmony_ci	.def_rx_buf_size		= CN6XXX_OQ_BUF_SIZE,
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	.nic_if_cfg[0] = {
34262306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
34362306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
34662306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
34962306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
35262306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		/* Num of desc for rx rings */
35562306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		/* Num of desc for tx rings */
35862306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
36162306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
36262306a36Sopenharmony_ci		 */
36362306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		.gmx_port_id			= 0,
36862306a36Sopenharmony_ci	},
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	.nic_if_cfg[1] = {
37162306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
37262306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
37562306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
37862306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
38162306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		/* Num of desc for rx rings */
38462306a36Sopenharmony_ci		.num_rx_descs			= CN6XXX_MAX_OQ_DESCRIPTORS,
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		/* Num of desc for tx rings */
38762306a36Sopenharmony_ci		.num_tx_descs			= CN6XXX_MAX_IQ_DESCRIPTORS,
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
39062306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
39162306a36Sopenharmony_ci		 */
39262306a36Sopenharmony_ci		.rx_buf_size			= CN6XXX_OQ_BUF_SIZE,
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		.gmx_port_id			= 1,
39762306a36Sopenharmony_ci	},
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/** Miscellaneous attributes */
40062306a36Sopenharmony_ci	.misc					= {
40162306a36Sopenharmony_ci		/* Host driver link query interval */
40262306a36Sopenharmony_ci		.oct_link_query_interval	= 100,
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		/* Octeon link query interval */
40562306a36Sopenharmony_ci		.host_link_query_interval	= 500,
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		.enable_sli_oq_bp		= 0,
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		/* Control queue group */
41062306a36Sopenharmony_ci		.ctrlq_grp			= 1,
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	,
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic struct octeon_config default_cn23xx_conf = {
41662306a36Sopenharmony_ci	.card_type                              = LIO_23XX,
41762306a36Sopenharmony_ci	.card_name                              = LIO_23XX_NAME,
41862306a36Sopenharmony_ci	/** IQ attributes */
41962306a36Sopenharmony_ci	.iq = {
42062306a36Sopenharmony_ci		.max_iqs		= CN23XX_CFG_IO_QUEUES,
42162306a36Sopenharmony_ci		.pending_list_size	= (CN23XX_DEFAULT_IQ_DESCRIPTORS *
42262306a36Sopenharmony_ci					   CN23XX_CFG_IO_QUEUES),
42362306a36Sopenharmony_ci		.instr_type		= OCTEON_64BYTE_INSTR,
42462306a36Sopenharmony_ci		.db_min			= CN23XX_DB_MIN,
42562306a36Sopenharmony_ci		.db_timeout		= CN23XX_DB_TIMEOUT,
42662306a36Sopenharmony_ci		.iq_intr_pkt		= CN23XX_DEF_IQ_INTR_THRESHOLD,
42762306a36Sopenharmony_ci	},
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/** OQ attributes */
43062306a36Sopenharmony_ci	.oq = {
43162306a36Sopenharmony_ci		.max_oqs		= CN23XX_CFG_IO_QUEUES,
43262306a36Sopenharmony_ci		.pkts_per_intr	= CN23XX_OQ_PKTSPER_INTR,
43362306a36Sopenharmony_ci		.refill_threshold	= CN23XX_OQ_REFIL_THRESHOLD,
43462306a36Sopenharmony_ci		.oq_intr_pkt	= CN23XX_OQ_INTR_PKT,
43562306a36Sopenharmony_ci		.oq_intr_time	= CN23XX_OQ_INTR_TIME,
43662306a36Sopenharmony_ci	},
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	.num_nic_ports				= DEFAULT_NUM_NIC_PORTS_23XX,
43962306a36Sopenharmony_ci	.num_def_rx_descs			= CN23XX_DEFAULT_OQ_DESCRIPTORS,
44062306a36Sopenharmony_ci	.num_def_tx_descs			= CN23XX_DEFAULT_IQ_DESCRIPTORS,
44162306a36Sopenharmony_ci	.def_rx_buf_size			= CN23XX_OQ_BUF_SIZE,
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* For ethernet interface 0:  Port cfg Attributes */
44462306a36Sopenharmony_ci	.nic_if_cfg[0] = {
44562306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
44662306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
44962306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
45262306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
45562306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/* Num of desc for rx rings */
45862306a36Sopenharmony_ci		.num_rx_descs			= CN23XX_DEFAULT_OQ_DESCRIPTORS,
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		/* Num of desc for tx rings */
46162306a36Sopenharmony_ci		.num_tx_descs			= CN23XX_DEFAULT_IQ_DESCRIPTORS,
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
46462306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
46562306a36Sopenharmony_ci		 */
46662306a36Sopenharmony_ci		.rx_buf_size			= CN23XX_OQ_BUF_SIZE,
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		.gmx_port_id			= 0,
47162306a36Sopenharmony_ci	},
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	.nic_if_cfg[1] = {
47462306a36Sopenharmony_ci		/* Max Txqs: Half for each of the two ports :max_iq/2 */
47562306a36Sopenharmony_ci		.max_txqs			= MAX_TXQS_PER_INTF,
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_txqs */
47862306a36Sopenharmony_ci		.num_txqs			= DEF_TXQS_PER_INTF,
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/* Max Rxqs: Half for each of the two ports :max_oq/2  */
48162306a36Sopenharmony_ci		.max_rxqs			= MAX_RXQS_PER_INTF,
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci		/* Actual configured value. Range could be: 1...max_rxqs */
48462306a36Sopenharmony_ci		.num_rxqs			= DEF_RXQS_PER_INTF,
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		/* Num of desc for rx rings */
48762306a36Sopenharmony_ci		.num_rx_descs			= CN23XX_DEFAULT_OQ_DESCRIPTORS,
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		/* Num of desc for tx rings */
49062306a36Sopenharmony_ci		.num_tx_descs			= CN23XX_DEFAULT_IQ_DESCRIPTORS,
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		/* SKB size, We need not change buf size even for Jumbo frames.
49362306a36Sopenharmony_ci		 * Octeon can send jumbo frames in 4 consecutive descriptors,
49462306a36Sopenharmony_ci		 */
49562306a36Sopenharmony_ci		.rx_buf_size			= CN23XX_OQ_BUF_SIZE,
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		.base_queue			= BASE_QUEUE_NOT_REQUESTED,
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		.gmx_port_id			= 1,
50062306a36Sopenharmony_ci	},
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	.misc					= {
50362306a36Sopenharmony_ci		/* Host driver link query interval */
50462306a36Sopenharmony_ci		.oct_link_query_interval	= 100,
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		/* Octeon link query interval */
50762306a36Sopenharmony_ci		.host_link_query_interval	= 500,
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		.enable_sli_oq_bp		= 0,
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		/* Control queue group */
51262306a36Sopenharmony_ci		.ctrlq_grp			= 1,
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic struct octeon_config_ptr {
51762306a36Sopenharmony_ci	u32 conf_type;
51862306a36Sopenharmony_ci} oct_conf_info[MAX_OCTEON_DEVICES] = {
51962306a36Sopenharmony_ci	{
52062306a36Sopenharmony_ci		OCTEON_CONFIG_TYPE_DEFAULT,
52162306a36Sopenharmony_ci	}, {
52262306a36Sopenharmony_ci		OCTEON_CONFIG_TYPE_DEFAULT,
52362306a36Sopenharmony_ci	}, {
52462306a36Sopenharmony_ci		OCTEON_CONFIG_TYPE_DEFAULT,
52562306a36Sopenharmony_ci	}, {
52662306a36Sopenharmony_ci		OCTEON_CONFIG_TYPE_DEFAULT,
52762306a36Sopenharmony_ci	},
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic char oct_dev_state_str[OCT_DEV_STATES + 1][32] = {
53162306a36Sopenharmony_ci	"BEGIN", "PCI-ENABLE-DONE", "PCI-MAP-DONE", "DISPATCH-INIT-DONE",
53262306a36Sopenharmony_ci	"IQ-INIT-DONE", "SCBUFF-POOL-INIT-DONE", "RESPLIST-INIT-DONE",
53362306a36Sopenharmony_ci	"DROQ-INIT-DONE", "MBOX-SETUP-DONE", "MSIX-ALLOC-VECTOR-DONE",
53462306a36Sopenharmony_ci	"INTR-SET-DONE", "IO-QUEUES-INIT-DONE", "CONSOLE-INIT-DONE",
53562306a36Sopenharmony_ci	"HOST-READY", "CORE-READY", "RUNNING", "IN-RESET",
53662306a36Sopenharmony_ci	"INVALID"
53762306a36Sopenharmony_ci};
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic char oct_dev_app_str[CVM_DRV_APP_COUNT + 1][32] = {
54062306a36Sopenharmony_ci	"BASE", "NIC", "UNKNOWN"};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic struct octeon_device *octeon_device[MAX_OCTEON_DEVICES];
54362306a36Sopenharmony_cistatic atomic_t adapter_refcounts[MAX_OCTEON_DEVICES];
54462306a36Sopenharmony_cistatic atomic_t adapter_fw_states[MAX_OCTEON_DEVICES];
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic u32 octeon_device_count;
54762306a36Sopenharmony_ci/* locks device array (i.e. octeon_device[]) */
54862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(octeon_devices_lock);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic struct octeon_core_setup core_setup[MAX_OCTEON_DEVICES];
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic void oct_set_config_info(int oct_id, int conf_type)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	if (conf_type < 0 || conf_type > (NUM_OCTEON_CONFS - 1))
55562306a36Sopenharmony_ci		conf_type = OCTEON_CONFIG_TYPE_DEFAULT;
55662306a36Sopenharmony_ci	oct_conf_info[oct_id].conf_type = conf_type;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_civoid octeon_init_device_list(int conf_type)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	int i;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	memset(octeon_device, 0, (sizeof(void *) * MAX_OCTEON_DEVICES));
56462306a36Sopenharmony_ci	for (i = 0; i <  MAX_OCTEON_DEVICES; i++)
56562306a36Sopenharmony_ci		oct_set_config_info(i, conf_type);
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_init_device_list);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void *__retrieve_octeon_config_info(struct octeon_device *oct,
57062306a36Sopenharmony_ci					   u16 card_type)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	u32 oct_id = oct->octeon_id;
57362306a36Sopenharmony_ci	void *ret = NULL;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	switch (oct_conf_info[oct_id].conf_type) {
57662306a36Sopenharmony_ci	case OCTEON_CONFIG_TYPE_DEFAULT:
57762306a36Sopenharmony_ci		if (oct->chip_id == OCTEON_CN66XX) {
57862306a36Sopenharmony_ci			ret = &default_cn66xx_conf;
57962306a36Sopenharmony_ci		} else if ((oct->chip_id == OCTEON_CN68XX) &&
58062306a36Sopenharmony_ci			   (card_type == LIO_210NV)) {
58162306a36Sopenharmony_ci			ret = &default_cn68xx_210nv_conf;
58262306a36Sopenharmony_ci		} else if ((oct->chip_id == OCTEON_CN68XX) &&
58362306a36Sopenharmony_ci			   (card_type == LIO_410NV)) {
58462306a36Sopenharmony_ci			ret = &default_cn68xx_conf;
58562306a36Sopenharmony_ci		} else if (oct->chip_id == OCTEON_CN23XX_PF_VID) {
58662306a36Sopenharmony_ci			ret = &default_cn23xx_conf;
58762306a36Sopenharmony_ci		} else if (oct->chip_id == OCTEON_CN23XX_VF_VID) {
58862306a36Sopenharmony_ci			ret = &default_cn23xx_conf;
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci		break;
59162306a36Sopenharmony_ci	default:
59262306a36Sopenharmony_ci		break;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci	return ret;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int __verify_octeon_config_info(struct octeon_device *oct, void *conf)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	switch (oct->chip_id) {
60062306a36Sopenharmony_ci	case OCTEON_CN66XX:
60162306a36Sopenharmony_ci	case OCTEON_CN68XX:
60262306a36Sopenharmony_ci		return lio_validate_cn6xxx_config_info(oct, conf);
60362306a36Sopenharmony_ci	case OCTEON_CN23XX_PF_VID:
60462306a36Sopenharmony_ci	case OCTEON_CN23XX_VF_VID:
60562306a36Sopenharmony_ci		return 0;
60662306a36Sopenharmony_ci	default:
60762306a36Sopenharmony_ci		break;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	return 1;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_civoid *oct_get_config_info(struct octeon_device *oct, u16 card_type)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	void *conf = NULL;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	conf = __retrieve_octeon_config_info(oct, card_type);
61862306a36Sopenharmony_ci	if (!conf)
61962306a36Sopenharmony_ci		return NULL;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if (__verify_octeon_config_info(oct, conf)) {
62262306a36Sopenharmony_ci		dev_err(&oct->pci_dev->dev, "Configuration verification failed\n");
62362306a36Sopenharmony_ci		return NULL;
62462306a36Sopenharmony_ci	}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	return conf;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cichar *lio_get_state_string(atomic_t *state_ptr)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	s32 istate = (s32)atomic_read(state_ptr);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	if (istate > OCT_DEV_STATES || istate < 0)
63462306a36Sopenharmony_ci		return oct_dev_state_str[OCT_DEV_STATE_INVALID];
63562306a36Sopenharmony_ci	return oct_dev_state_str[istate];
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lio_get_state_string);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cistatic char *get_oct_app_string(u32 app_mode)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	if (app_mode <= CVM_DRV_APP_END)
64262306a36Sopenharmony_ci		return oct_dev_app_str[app_mode - CVM_DRV_APP_START];
64362306a36Sopenharmony_ci	return oct_dev_app_str[CVM_DRV_INVALID_APP - CVM_DRV_APP_START];
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_civoid octeon_free_device_mem(struct octeon_device *oct)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	int i;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	for (i = 0; i < MAX_OCTEON_OUTPUT_QUEUES(oct); i++) {
65162306a36Sopenharmony_ci		if (oct->io_qmask.oq & BIT_ULL(i))
65262306a36Sopenharmony_ci			vfree(oct->droq[i]);
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	for (i = 0; i < MAX_OCTEON_INSTR_QUEUES(oct); i++) {
65662306a36Sopenharmony_ci		if (oct->io_qmask.iq & BIT_ULL(i))
65762306a36Sopenharmony_ci			vfree(oct->instr_queue[i]);
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	i = oct->octeon_id;
66162306a36Sopenharmony_ci	vfree(oct);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	octeon_device[i] = NULL;
66462306a36Sopenharmony_ci	octeon_device_count--;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_free_device_mem);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic struct octeon_device *octeon_allocate_device_mem(u32 pci_id,
66962306a36Sopenharmony_ci							u32 priv_size)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct octeon_device *oct;
67262306a36Sopenharmony_ci	u8 *buf = NULL;
67362306a36Sopenharmony_ci	u32 octdevsize = 0, configsize = 0, size;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	switch (pci_id) {
67662306a36Sopenharmony_ci	case OCTEON_CN68XX:
67762306a36Sopenharmony_ci	case OCTEON_CN66XX:
67862306a36Sopenharmony_ci		configsize = sizeof(struct octeon_cn6xxx);
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	case OCTEON_CN23XX_PF_VID:
68262306a36Sopenharmony_ci		configsize = sizeof(struct octeon_cn23xx_pf);
68362306a36Sopenharmony_ci		break;
68462306a36Sopenharmony_ci	case OCTEON_CN23XX_VF_VID:
68562306a36Sopenharmony_ci		configsize = sizeof(struct octeon_cn23xx_vf);
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci	default:
68862306a36Sopenharmony_ci		pr_err("%s: Unknown PCI Device: 0x%x\n",
68962306a36Sopenharmony_ci		       __func__,
69062306a36Sopenharmony_ci		       pci_id);
69162306a36Sopenharmony_ci		return NULL;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (configsize & 0x7)
69562306a36Sopenharmony_ci		configsize += (8 - (configsize & 0x7));
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	octdevsize = sizeof(struct octeon_device);
69862306a36Sopenharmony_ci	if (octdevsize & 0x7)
69962306a36Sopenharmony_ci		octdevsize += (8 - (octdevsize & 0x7));
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (priv_size & 0x7)
70262306a36Sopenharmony_ci		priv_size += (8 - (priv_size & 0x7));
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	size = octdevsize + priv_size + configsize +
70562306a36Sopenharmony_ci		(sizeof(struct octeon_dispatch) * DISPATCH_LIST_SIZE);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	buf = vzalloc(size);
70862306a36Sopenharmony_ci	if (!buf)
70962306a36Sopenharmony_ci		return NULL;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	oct = (struct octeon_device *)buf;
71262306a36Sopenharmony_ci	oct->priv = (void *)(buf + octdevsize);
71362306a36Sopenharmony_ci	oct->chip = (void *)(buf + octdevsize + priv_size);
71462306a36Sopenharmony_ci	oct->dispatch.dlist = (struct octeon_dispatch *)
71562306a36Sopenharmony_ci		(buf + octdevsize + priv_size + configsize);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	return oct;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistruct octeon_device *octeon_allocate_device(u32 pci_id,
72162306a36Sopenharmony_ci					     u32 priv_size)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	u32 oct_idx = 0;
72462306a36Sopenharmony_ci	struct octeon_device *oct = NULL;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	spin_lock(&octeon_devices_lock);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	for (oct_idx = 0; oct_idx < MAX_OCTEON_DEVICES; oct_idx++)
72962306a36Sopenharmony_ci		if (!octeon_device[oct_idx])
73062306a36Sopenharmony_ci			break;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (oct_idx < MAX_OCTEON_DEVICES) {
73362306a36Sopenharmony_ci		oct = octeon_allocate_device_mem(pci_id, priv_size);
73462306a36Sopenharmony_ci		if (oct) {
73562306a36Sopenharmony_ci			octeon_device_count++;
73662306a36Sopenharmony_ci			octeon_device[oct_idx] = oct;
73762306a36Sopenharmony_ci		}
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	spin_unlock(&octeon_devices_lock);
74162306a36Sopenharmony_ci	if (!oct)
74262306a36Sopenharmony_ci		return NULL;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	spin_lock_init(&oct->pci_win_lock);
74562306a36Sopenharmony_ci	spin_lock_init(&oct->mem_access_lock);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	oct->octeon_id = oct_idx;
74862306a36Sopenharmony_ci	snprintf(oct->device_name, sizeof(oct->device_name),
74962306a36Sopenharmony_ci		 "LiquidIO%d", (oct->octeon_id));
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return oct;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_allocate_device);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/** Register a device's bus location at initialization time.
75662306a36Sopenharmony_ci *  @param octeon_dev - pointer to the octeon device structure.
75762306a36Sopenharmony_ci *  @param bus        - PCIe bus #
75862306a36Sopenharmony_ci *  @param dev        - PCIe device #
75962306a36Sopenharmony_ci *  @param func       - PCIe function #
76062306a36Sopenharmony_ci *  @param is_pf      - TRUE for PF, FALSE for VF
76162306a36Sopenharmony_ci *  @return reference count of device's adapter
76262306a36Sopenharmony_ci */
76362306a36Sopenharmony_ciint octeon_register_device(struct octeon_device *oct,
76462306a36Sopenharmony_ci			   int bus, int dev, int func, int is_pf)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	int idx, refcount;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	oct->loc.bus = bus;
76962306a36Sopenharmony_ci	oct->loc.dev = dev;
77062306a36Sopenharmony_ci	oct->loc.func = func;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	oct->adapter_refcount = &adapter_refcounts[oct->octeon_id];
77362306a36Sopenharmony_ci	atomic_set(oct->adapter_refcount, 0);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* Like the reference count, the f/w state is shared 'per-adapter' */
77662306a36Sopenharmony_ci	oct->adapter_fw_state = &adapter_fw_states[oct->octeon_id];
77762306a36Sopenharmony_ci	atomic_set(oct->adapter_fw_state, FW_NEEDS_TO_BE_LOADED);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	spin_lock(&octeon_devices_lock);
78062306a36Sopenharmony_ci	for (idx = (int)oct->octeon_id - 1; idx >= 0; idx--) {
78162306a36Sopenharmony_ci		if (!octeon_device[idx]) {
78262306a36Sopenharmony_ci			dev_err(&oct->pci_dev->dev,
78362306a36Sopenharmony_ci				"%s: Internal driver error, missing dev",
78462306a36Sopenharmony_ci				__func__);
78562306a36Sopenharmony_ci			spin_unlock(&octeon_devices_lock);
78662306a36Sopenharmony_ci			atomic_inc(oct->adapter_refcount);
78762306a36Sopenharmony_ci			return 1; /* here, refcount is guaranteed to be 1 */
78862306a36Sopenharmony_ci		}
78962306a36Sopenharmony_ci		/* If another device is at same bus/dev, use its refcounter
79062306a36Sopenharmony_ci		 * (and f/w state variable).
79162306a36Sopenharmony_ci		 */
79262306a36Sopenharmony_ci		if ((octeon_device[idx]->loc.bus == bus) &&
79362306a36Sopenharmony_ci		    (octeon_device[idx]->loc.dev == dev)) {
79462306a36Sopenharmony_ci			oct->adapter_refcount =
79562306a36Sopenharmony_ci				octeon_device[idx]->adapter_refcount;
79662306a36Sopenharmony_ci			oct->adapter_fw_state =
79762306a36Sopenharmony_ci				octeon_device[idx]->adapter_fw_state;
79862306a36Sopenharmony_ci			break;
79962306a36Sopenharmony_ci		}
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci	spin_unlock(&octeon_devices_lock);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	atomic_inc(oct->adapter_refcount);
80462306a36Sopenharmony_ci	refcount = atomic_read(oct->adapter_refcount);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	dev_dbg(&oct->pci_dev->dev, "%s: %02x:%02x:%d refcount %u", __func__,
80762306a36Sopenharmony_ci		oct->loc.bus, oct->loc.dev, oct->loc.func, refcount);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	return refcount;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_register_device);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci/** Deregister a device at de-initialization time.
81462306a36Sopenharmony_ci *  @param octeon_dev - pointer to the octeon device structure.
81562306a36Sopenharmony_ci *  @return reference count of device's adapter
81662306a36Sopenharmony_ci */
81762306a36Sopenharmony_ciint octeon_deregister_device(struct octeon_device *oct)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	int refcount;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	atomic_dec(oct->adapter_refcount);
82262306a36Sopenharmony_ci	refcount = atomic_read(oct->adapter_refcount);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	dev_dbg(&oct->pci_dev->dev, "%s: %04d:%02d:%d refcount %u", __func__,
82562306a36Sopenharmony_ci		oct->loc.bus, oct->loc.dev, oct->loc.func, refcount);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return refcount;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_deregister_device);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ciint
83262306a36Sopenharmony_ciocteon_allocate_ioq_vector(struct octeon_device *oct, u32 num_ioqs)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct octeon_ioq_vector *ioq_vector;
83562306a36Sopenharmony_ci	int cpu_num;
83662306a36Sopenharmony_ci	int size;
83762306a36Sopenharmony_ci	int i;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	size = sizeof(struct octeon_ioq_vector) * num_ioqs;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	oct->ioq_vector = vzalloc(size);
84262306a36Sopenharmony_ci	if (!oct->ioq_vector)
84362306a36Sopenharmony_ci		return -1;
84462306a36Sopenharmony_ci	for (i = 0; i < num_ioqs; i++) {
84562306a36Sopenharmony_ci		ioq_vector		= &oct->ioq_vector[i];
84662306a36Sopenharmony_ci		ioq_vector->oct_dev	= oct;
84762306a36Sopenharmony_ci		ioq_vector->iq_index	= i;
84862306a36Sopenharmony_ci		ioq_vector->droq_index	= i;
84962306a36Sopenharmony_ci		ioq_vector->mbox	= oct->mbox[i];
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		cpu_num = i % num_online_cpus();
85262306a36Sopenharmony_ci		cpumask_set_cpu(cpu_num, &ioq_vector->affinity_mask);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		if (oct->chip_id == OCTEON_CN23XX_PF_VID)
85562306a36Sopenharmony_ci			ioq_vector->ioq_num	= i + oct->sriov_info.pf_srn;
85662306a36Sopenharmony_ci		else
85762306a36Sopenharmony_ci			ioq_vector->ioq_num	= i;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	return 0;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_allocate_ioq_vector);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_civoid
86562306a36Sopenharmony_ciocteon_free_ioq_vector(struct octeon_device *oct)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	vfree(oct->ioq_vector);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_free_ioq_vector);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/* this function is only for setting up the first queue */
87262306a36Sopenharmony_ciint octeon_setup_instr_queues(struct octeon_device *oct)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	u32 num_descs = 0;
87562306a36Sopenharmony_ci	u32 iq_no = 0;
87662306a36Sopenharmony_ci	union oct_txpciq txpciq;
87762306a36Sopenharmony_ci	int numa_node = dev_to_node(&oct->pci_dev->dev);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct))
88062306a36Sopenharmony_ci		num_descs =
88162306a36Sopenharmony_ci			CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn6xxx));
88262306a36Sopenharmony_ci	else if (OCTEON_CN23XX_PF(oct))
88362306a36Sopenharmony_ci		num_descs = CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn23xx_pf));
88462306a36Sopenharmony_ci	else if (OCTEON_CN23XX_VF(oct))
88562306a36Sopenharmony_ci		num_descs = CFG_GET_NUM_DEF_TX_DESCS(CHIP_CONF(oct, cn23xx_vf));
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	oct->num_iqs = 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	oct->instr_queue[0] = vzalloc_node(sizeof(*oct->instr_queue[0]),
89062306a36Sopenharmony_ci				numa_node);
89162306a36Sopenharmony_ci	if (!oct->instr_queue[0])
89262306a36Sopenharmony_ci		oct->instr_queue[0] =
89362306a36Sopenharmony_ci			vzalloc(sizeof(struct octeon_instr_queue));
89462306a36Sopenharmony_ci	if (!oct->instr_queue[0])
89562306a36Sopenharmony_ci		return 1;
89662306a36Sopenharmony_ci	memset(oct->instr_queue[0], 0, sizeof(struct octeon_instr_queue));
89762306a36Sopenharmony_ci	oct->instr_queue[0]->q_index = 0;
89862306a36Sopenharmony_ci	oct->instr_queue[0]->app_ctx = (void *)(size_t)0;
89962306a36Sopenharmony_ci	oct->instr_queue[0]->ifidx = 0;
90062306a36Sopenharmony_ci	txpciq.u64 = 0;
90162306a36Sopenharmony_ci	txpciq.s.q_no = iq_no;
90262306a36Sopenharmony_ci	txpciq.s.pkind = oct->pfvf_hsword.pkind;
90362306a36Sopenharmony_ci	txpciq.s.use_qpg = 0;
90462306a36Sopenharmony_ci	txpciq.s.qpg = 0;
90562306a36Sopenharmony_ci	if (octeon_init_instr_queue(oct, txpciq, num_descs)) {
90662306a36Sopenharmony_ci		/* prevent memory leak */
90762306a36Sopenharmony_ci		vfree(oct->instr_queue[0]);
90862306a36Sopenharmony_ci		oct->instr_queue[0] = NULL;
90962306a36Sopenharmony_ci		return 1;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	oct->num_iqs++;
91362306a36Sopenharmony_ci	return 0;
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_setup_instr_queues);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ciint octeon_setup_output_queues(struct octeon_device *oct)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	u32 num_descs = 0;
92062306a36Sopenharmony_ci	u32 desc_size = 0;
92162306a36Sopenharmony_ci	u32 oq_no = 0;
92262306a36Sopenharmony_ci	int numa_node = dev_to_node(&oct->pci_dev->dev);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct)) {
92562306a36Sopenharmony_ci		num_descs =
92662306a36Sopenharmony_ci			CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn6xxx));
92762306a36Sopenharmony_ci		desc_size =
92862306a36Sopenharmony_ci			CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn6xxx));
92962306a36Sopenharmony_ci	} else if (OCTEON_CN23XX_PF(oct)) {
93062306a36Sopenharmony_ci		num_descs = CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn23xx_pf));
93162306a36Sopenharmony_ci		desc_size = CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn23xx_pf));
93262306a36Sopenharmony_ci	} else if (OCTEON_CN23XX_VF(oct)) {
93362306a36Sopenharmony_ci		num_descs = CFG_GET_NUM_DEF_RX_DESCS(CHIP_CONF(oct, cn23xx_vf));
93462306a36Sopenharmony_ci		desc_size = CFG_GET_DEF_RX_BUF_SIZE(CHIP_CONF(oct, cn23xx_vf));
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	oct->num_oqs = 0;
93762306a36Sopenharmony_ci	oct->droq[0] = vzalloc_node(sizeof(*oct->droq[0]), numa_node);
93862306a36Sopenharmony_ci	if (!oct->droq[0])
93962306a36Sopenharmony_ci		oct->droq[0] = vzalloc(sizeof(*oct->droq[0]));
94062306a36Sopenharmony_ci	if (!oct->droq[0])
94162306a36Sopenharmony_ci		return 1;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	if (octeon_init_droq(oct, oq_no, num_descs, desc_size, NULL)) {
94462306a36Sopenharmony_ci		vfree(oct->droq[oq_no]);
94562306a36Sopenharmony_ci		oct->droq[oq_no] = NULL;
94662306a36Sopenharmony_ci		return 1;
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci	oct->num_oqs++;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_setup_output_queues);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ciint octeon_set_io_queues_off(struct octeon_device *oct)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	int loop = BUSY_READING_REG_VF_LOOP_COUNT;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct)) {
95962306a36Sopenharmony_ci		octeon_write_csr(oct, CN6XXX_SLI_PKT_INSTR_ENB, 0);
96062306a36Sopenharmony_ci		octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, 0);
96162306a36Sopenharmony_ci	} else if (oct->chip_id == OCTEON_CN23XX_VF_VID) {
96262306a36Sopenharmony_ci		u32 q_no;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		/* IOQs will already be in reset.
96562306a36Sopenharmony_ci		 * If RST bit is set, wait for quiet bit to be set.
96662306a36Sopenharmony_ci		 * Once quiet bit is set, clear the RST bit.
96762306a36Sopenharmony_ci		 */
96862306a36Sopenharmony_ci		for (q_no = 0; q_no < oct->sriov_info.rings_per_vf; q_no++) {
96962306a36Sopenharmony_ci			u64 reg_val = octeon_read_csr64(
97062306a36Sopenharmony_ci				oct, CN23XX_VF_SLI_IQ_PKT_CONTROL64(q_no));
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci			while ((reg_val & CN23XX_PKT_INPUT_CTL_RST) &&
97362306a36Sopenharmony_ci			       !(reg_val &  CN23XX_PKT_INPUT_CTL_QUIET) &&
97462306a36Sopenharmony_ci			       loop) {
97562306a36Sopenharmony_ci				reg_val = octeon_read_csr64(
97662306a36Sopenharmony_ci					oct, CN23XX_SLI_IQ_PKT_CONTROL64(q_no));
97762306a36Sopenharmony_ci				loop--;
97862306a36Sopenharmony_ci			}
97962306a36Sopenharmony_ci			if (!loop) {
98062306a36Sopenharmony_ci				dev_err(&oct->pci_dev->dev,
98162306a36Sopenharmony_ci					"clearing the reset reg failed or setting the quiet reg failed for qno: %u\n",
98262306a36Sopenharmony_ci					q_no);
98362306a36Sopenharmony_ci				return -1;
98462306a36Sopenharmony_ci			}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci			reg_val = reg_val & ~CN23XX_PKT_INPUT_CTL_RST;
98762306a36Sopenharmony_ci			octeon_write_csr64(oct,
98862306a36Sopenharmony_ci					   CN23XX_SLI_IQ_PKT_CONTROL64(q_no),
98962306a36Sopenharmony_ci					   reg_val);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci			reg_val = octeon_read_csr64(
99262306a36Sopenharmony_ci					oct, CN23XX_SLI_IQ_PKT_CONTROL64(q_no));
99362306a36Sopenharmony_ci			if (reg_val & CN23XX_PKT_INPUT_CTL_RST) {
99462306a36Sopenharmony_ci				dev_err(&oct->pci_dev->dev,
99562306a36Sopenharmony_ci					"unable to reset qno %u\n", q_no);
99662306a36Sopenharmony_ci				return -1;
99762306a36Sopenharmony_ci			}
99862306a36Sopenharmony_ci		}
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_set_io_queues_off);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_civoid octeon_set_droq_pkt_op(struct octeon_device *oct,
100562306a36Sopenharmony_ci			    u32 q_no,
100662306a36Sopenharmony_ci			    u32 enable)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	u32 reg_val = 0;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* Disable the i/p and o/p queues for this Octeon. */
101162306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct)) {
101262306a36Sopenharmony_ci		reg_val = octeon_read_csr(oct, CN6XXX_SLI_PKT_OUT_ENB);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci		if (enable)
101562306a36Sopenharmony_ci			reg_val = reg_val | (1 << q_no);
101662306a36Sopenharmony_ci		else
101762306a36Sopenharmony_ci			reg_val = reg_val & (~(1 << q_no));
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci		octeon_write_csr(oct, CN6XXX_SLI_PKT_OUT_ENB, reg_val);
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ciint octeon_init_dispatch_list(struct octeon_device *oct)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	u32 i;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	oct->dispatch.count = 0;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	for (i = 0; i < DISPATCH_LIST_SIZE; i++) {
103062306a36Sopenharmony_ci		oct->dispatch.dlist[i].opcode = 0;
103162306a36Sopenharmony_ci		INIT_LIST_HEAD(&oct->dispatch.dlist[i].list);
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	for (i = 0; i <= REQTYPE_LAST; i++)
103562306a36Sopenharmony_ci		octeon_register_reqtype_free_fn(oct, i, NULL);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	spin_lock_init(&oct->dispatch.lock);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	return 0;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_init_dispatch_list);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_civoid octeon_delete_dispatch_list(struct octeon_device *oct)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	u32 i;
104662306a36Sopenharmony_ci	struct list_head freelist, *temp, *tmp2;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	INIT_LIST_HEAD(&freelist);
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	spin_lock_bh(&oct->dispatch.lock);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	for (i = 0; i < DISPATCH_LIST_SIZE; i++) {
105362306a36Sopenharmony_ci		struct list_head *dispatch;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		dispatch = &oct->dispatch.dlist[i].list;
105662306a36Sopenharmony_ci		while (dispatch->next != dispatch) {
105762306a36Sopenharmony_ci			temp = dispatch->next;
105862306a36Sopenharmony_ci			list_move_tail(temp, &freelist);
105962306a36Sopenharmony_ci		}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		oct->dispatch.dlist[i].opcode = 0;
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	oct->dispatch.count = 0;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	spin_unlock_bh(&oct->dispatch.lock);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	list_for_each_safe(temp, tmp2, &freelist) {
106962306a36Sopenharmony_ci		list_del(temp);
107062306a36Sopenharmony_ci		kfree(temp);
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_delete_dispatch_list);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ciocteon_dispatch_fn_t
107662306a36Sopenharmony_ciocteon_get_dispatch(struct octeon_device *octeon_dev, u16 opcode,
107762306a36Sopenharmony_ci		    u16 subcode)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	u32 idx;
108062306a36Sopenharmony_ci	struct list_head *dispatch;
108162306a36Sopenharmony_ci	octeon_dispatch_fn_t fn = NULL;
108262306a36Sopenharmony_ci	u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	idx = combined_opcode & OCTEON_OPCODE_MASK;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	spin_lock_bh(&octeon_dev->dispatch.lock);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (octeon_dev->dispatch.count == 0) {
108962306a36Sopenharmony_ci		spin_unlock_bh(&octeon_dev->dispatch.lock);
109062306a36Sopenharmony_ci		return NULL;
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (!(octeon_dev->dispatch.dlist[idx].opcode)) {
109462306a36Sopenharmony_ci		spin_unlock_bh(&octeon_dev->dispatch.lock);
109562306a36Sopenharmony_ci		return NULL;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (octeon_dev->dispatch.dlist[idx].opcode == combined_opcode) {
109962306a36Sopenharmony_ci		fn = octeon_dev->dispatch.dlist[idx].dispatch_fn;
110062306a36Sopenharmony_ci	} else {
110162306a36Sopenharmony_ci		list_for_each(dispatch,
110262306a36Sopenharmony_ci			      &octeon_dev->dispatch.dlist[idx].list) {
110362306a36Sopenharmony_ci			if (((struct octeon_dispatch *)dispatch)->opcode ==
110462306a36Sopenharmony_ci			    combined_opcode) {
110562306a36Sopenharmony_ci				fn = ((struct octeon_dispatch *)
110662306a36Sopenharmony_ci				      dispatch)->dispatch_fn;
110762306a36Sopenharmony_ci				break;
110862306a36Sopenharmony_ci			}
110962306a36Sopenharmony_ci		}
111062306a36Sopenharmony_ci	}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	spin_unlock_bh(&octeon_dev->dispatch.lock);
111362306a36Sopenharmony_ci	return fn;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci/* octeon_register_dispatch_fn
111762306a36Sopenharmony_ci * Parameters:
111862306a36Sopenharmony_ci *   octeon_id - id of the octeon device.
111962306a36Sopenharmony_ci *   opcode    - opcode for which driver should call the registered function
112062306a36Sopenharmony_ci *   subcode   - subcode for which driver should call the registered function
112162306a36Sopenharmony_ci *   fn        - The function to call when a packet with "opcode" arrives in
112262306a36Sopenharmony_ci *		  octeon output queues.
112362306a36Sopenharmony_ci *   fn_arg    - The argument to be passed when calling function "fn".
112462306a36Sopenharmony_ci * Description:
112562306a36Sopenharmony_ci *   Registers a function and its argument to be called when a packet
112662306a36Sopenharmony_ci *   arrives in Octeon output queues with "opcode".
112762306a36Sopenharmony_ci * Returns:
112862306a36Sopenharmony_ci *   Success: 0
112962306a36Sopenharmony_ci *   Failure: 1
113062306a36Sopenharmony_ci * Locks:
113162306a36Sopenharmony_ci *   No locks are held.
113262306a36Sopenharmony_ci */
113362306a36Sopenharmony_ciint
113462306a36Sopenharmony_ciocteon_register_dispatch_fn(struct octeon_device *oct,
113562306a36Sopenharmony_ci			    u16 opcode,
113662306a36Sopenharmony_ci			    u16 subcode,
113762306a36Sopenharmony_ci			    octeon_dispatch_fn_t fn, void *fn_arg)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	u32 idx;
114062306a36Sopenharmony_ci	octeon_dispatch_fn_t pfn;
114162306a36Sopenharmony_ci	u16 combined_opcode = OPCODE_SUBCODE(opcode, subcode);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	idx = combined_opcode & OCTEON_OPCODE_MASK;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	spin_lock_bh(&oct->dispatch.lock);
114662306a36Sopenharmony_ci	/* Add dispatch function to first level of lookup table */
114762306a36Sopenharmony_ci	if (oct->dispatch.dlist[idx].opcode == 0) {
114862306a36Sopenharmony_ci		oct->dispatch.dlist[idx].opcode = combined_opcode;
114962306a36Sopenharmony_ci		oct->dispatch.dlist[idx].dispatch_fn = fn;
115062306a36Sopenharmony_ci		oct->dispatch.dlist[idx].arg = fn_arg;
115162306a36Sopenharmony_ci		oct->dispatch.count++;
115262306a36Sopenharmony_ci		spin_unlock_bh(&oct->dispatch.lock);
115362306a36Sopenharmony_ci		return 0;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	spin_unlock_bh(&oct->dispatch.lock);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/* Check if there was a function already registered for this
115962306a36Sopenharmony_ci	 * opcode/subcode.
116062306a36Sopenharmony_ci	 */
116162306a36Sopenharmony_ci	pfn = octeon_get_dispatch(oct, opcode, subcode);
116262306a36Sopenharmony_ci	if (!pfn) {
116362306a36Sopenharmony_ci		struct octeon_dispatch *dispatch;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		dev_dbg(&oct->pci_dev->dev,
116662306a36Sopenharmony_ci			"Adding opcode to dispatch list linked list\n");
116762306a36Sopenharmony_ci		dispatch = kmalloc(sizeof(*dispatch), GFP_KERNEL);
116862306a36Sopenharmony_ci		if (!dispatch)
116962306a36Sopenharmony_ci			return 1;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		dispatch->opcode = combined_opcode;
117262306a36Sopenharmony_ci		dispatch->dispatch_fn = fn;
117362306a36Sopenharmony_ci		dispatch->arg = fn_arg;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci		/* Add dispatch function to linked list of fn ptrs
117662306a36Sopenharmony_ci		 * at the hashed index.
117762306a36Sopenharmony_ci		 */
117862306a36Sopenharmony_ci		spin_lock_bh(&oct->dispatch.lock);
117962306a36Sopenharmony_ci		list_add(&dispatch->list, &oct->dispatch.dlist[idx].list);
118062306a36Sopenharmony_ci		oct->dispatch.count++;
118162306a36Sopenharmony_ci		spin_unlock_bh(&oct->dispatch.lock);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	} else {
118462306a36Sopenharmony_ci		if (pfn == fn &&
118562306a36Sopenharmony_ci		    octeon_get_dispatch_arg(oct, opcode, subcode) == fn_arg)
118662306a36Sopenharmony_ci			return 0;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		dev_err(&oct->pci_dev->dev,
118962306a36Sopenharmony_ci			"Found previously registered dispatch fn for opcode/subcode: %x/%x\n",
119062306a36Sopenharmony_ci			opcode, subcode);
119162306a36Sopenharmony_ci		return 1;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	return 0;
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_register_dispatch_fn);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ciint octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	u32 i;
120162306a36Sopenharmony_ci	char app_name[16];
120262306a36Sopenharmony_ci	struct octeon_device *oct = (struct octeon_device *)buf;
120362306a36Sopenharmony_ci	struct octeon_recv_pkt *recv_pkt = recv_info->recv_pkt;
120462306a36Sopenharmony_ci	struct octeon_core_setup *cs = NULL;
120562306a36Sopenharmony_ci	u32 num_nic_ports = 0;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct))
120862306a36Sopenharmony_ci		num_nic_ports =
120962306a36Sopenharmony_ci			CFG_GET_NUM_NIC_PORTS(CHIP_CONF(oct, cn6xxx));
121062306a36Sopenharmony_ci	else if (OCTEON_CN23XX_PF(oct))
121162306a36Sopenharmony_ci		num_nic_ports =
121262306a36Sopenharmony_ci			CFG_GET_NUM_NIC_PORTS(CHIP_CONF(oct, cn23xx_pf));
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (atomic_read(&oct->status) >= OCT_DEV_RUNNING) {
121562306a36Sopenharmony_ci		dev_err(&oct->pci_dev->dev, "Received CORE OK when device state is 0x%x\n",
121662306a36Sopenharmony_ci			atomic_read(&oct->status));
121762306a36Sopenharmony_ci		goto core_drv_init_err;
121862306a36Sopenharmony_ci	}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	strncpy(app_name,
122162306a36Sopenharmony_ci		get_oct_app_string(
122262306a36Sopenharmony_ci		(u32)recv_pkt->rh.r_core_drv_init.app_mode),
122362306a36Sopenharmony_ci		sizeof(app_name) - 1);
122462306a36Sopenharmony_ci	oct->app_mode = (u32)recv_pkt->rh.r_core_drv_init.app_mode;
122562306a36Sopenharmony_ci	if (recv_pkt->rh.r_core_drv_init.app_mode == CVM_DRV_NIC_APP) {
122662306a36Sopenharmony_ci		oct->fw_info.max_nic_ports =
122762306a36Sopenharmony_ci			(u32)recv_pkt->rh.r_core_drv_init.max_nic_ports;
122862306a36Sopenharmony_ci		oct->fw_info.num_gmx_ports =
122962306a36Sopenharmony_ci			(u32)recv_pkt->rh.r_core_drv_init.num_gmx_ports;
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (oct->fw_info.max_nic_ports < num_nic_ports) {
123362306a36Sopenharmony_ci		dev_err(&oct->pci_dev->dev,
123462306a36Sopenharmony_ci			"Config has more ports than firmware allows (%d > %d).\n",
123562306a36Sopenharmony_ci			num_nic_ports, oct->fw_info.max_nic_ports);
123662306a36Sopenharmony_ci		goto core_drv_init_err;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci	oct->fw_info.app_cap_flags = recv_pkt->rh.r_core_drv_init.app_cap_flags;
123962306a36Sopenharmony_ci	oct->fw_info.app_mode = (u32)recv_pkt->rh.r_core_drv_init.app_mode;
124062306a36Sopenharmony_ci	oct->pfvf_hsword.app_mode = (u32)recv_pkt->rh.r_core_drv_init.app_mode;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	oct->pfvf_hsword.pkind = recv_pkt->rh.r_core_drv_init.pkind;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	for (i = 0; i < oct->num_iqs; i++)
124562306a36Sopenharmony_ci		oct->instr_queue[i]->txpciq.s.pkind = oct->pfvf_hsword.pkind;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	atomic_set(&oct->status, OCT_DEV_CORE_OK);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	cs = &core_setup[oct->octeon_id];
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	if (recv_pkt->buffer_size[0] != (sizeof(*cs) + OCT_DROQ_INFO_SIZE)) {
125262306a36Sopenharmony_ci		dev_dbg(&oct->pci_dev->dev, "Core setup bytes expected %u found %d\n",
125362306a36Sopenharmony_ci			(u32)sizeof(*cs),
125462306a36Sopenharmony_ci			recv_pkt->buffer_size[0]);
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	memcpy(cs, get_rbd(
125862306a36Sopenharmony_ci	       recv_pkt->buffer_ptr[0]) + OCT_DROQ_INFO_SIZE, sizeof(*cs));
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	strncpy(oct->boardinfo.name, cs->boardname, OCT_BOARD_NAME);
126162306a36Sopenharmony_ci	strncpy(oct->boardinfo.serial_number, cs->board_serial_number,
126262306a36Sopenharmony_ci		OCT_SERIAL_LEN);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	octeon_swap_8B_data((u64 *)cs, (sizeof(*cs) >> 3));
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	oct->boardinfo.major = cs->board_rev_major;
126762306a36Sopenharmony_ci	oct->boardinfo.minor = cs->board_rev_minor;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	dev_info(&oct->pci_dev->dev,
127062306a36Sopenharmony_ci		 "Running %s (%llu Hz)\n",
127162306a36Sopenharmony_ci		 app_name, CVM_CAST64(cs->corefreq));
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cicore_drv_init_err:
127462306a36Sopenharmony_ci	for (i = 0; i < recv_pkt->buffer_count; i++)
127562306a36Sopenharmony_ci		recv_buffer_free(recv_pkt->buffer_ptr[i]);
127662306a36Sopenharmony_ci	octeon_free_recv_info(recv_info);
127762306a36Sopenharmony_ci	return 0;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_core_drv_init);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ciint octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no)
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	if (oct && (q_no < MAX_OCTEON_INSTR_QUEUES(oct)) &&
128562306a36Sopenharmony_ci	    (oct->io_qmask.iq & BIT_ULL(q_no)))
128662306a36Sopenharmony_ci		return oct->instr_queue[q_no]->max_count;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	return -1;
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_get_tx_qsize);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ciint octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	if (oct && (q_no < MAX_OCTEON_OUTPUT_QUEUES(oct)) &&
129562306a36Sopenharmony_ci	    (oct->io_qmask.oq & BIT_ULL(q_no)))
129662306a36Sopenharmony_ci		return oct->droq[q_no]->max_count;
129762306a36Sopenharmony_ci	return -1;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_get_rx_qsize);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci/* Retruns the host firmware handshake OCTEON specific configuration */
130262306a36Sopenharmony_cistruct octeon_config *octeon_get_conf(struct octeon_device *oct)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	struct octeon_config *default_oct_conf = NULL;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* check the OCTEON Device model & return the corresponding octeon
130762306a36Sopenharmony_ci	 * configuration
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct)) {
131162306a36Sopenharmony_ci		default_oct_conf =
131262306a36Sopenharmony_ci			(struct octeon_config *)(CHIP_CONF(oct, cn6xxx));
131362306a36Sopenharmony_ci	} else if (OCTEON_CN23XX_PF(oct)) {
131462306a36Sopenharmony_ci		default_oct_conf = (struct octeon_config *)
131562306a36Sopenharmony_ci			(CHIP_CONF(oct, cn23xx_pf));
131662306a36Sopenharmony_ci	} else if (OCTEON_CN23XX_VF(oct)) {
131762306a36Sopenharmony_ci		default_oct_conf = (struct octeon_config *)
131862306a36Sopenharmony_ci			(CHIP_CONF(oct, cn23xx_vf));
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci	return default_oct_conf;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_get_conf);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci/* scratch register address is same in all the OCT-II and CN70XX models */
132562306a36Sopenharmony_ci#define CNXX_SLI_SCRATCH1   0x3C0
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci/* Get the octeon device pointer.
132862306a36Sopenharmony_ci *  @param octeon_id  - The id for which the octeon device pointer is required.
132962306a36Sopenharmony_ci *  @return Success: Octeon device pointer.
133062306a36Sopenharmony_ci *  @return Failure: NULL.
133162306a36Sopenharmony_ci */
133262306a36Sopenharmony_cistruct octeon_device *lio_get_device(u32 octeon_id)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	if (octeon_id >= MAX_OCTEON_DEVICES)
133562306a36Sopenharmony_ci		return NULL;
133662306a36Sopenharmony_ci	else
133762306a36Sopenharmony_ci		return octeon_device[octeon_id];
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lio_get_device);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ciu64 lio_pci_readq(struct octeon_device *oct, u64 addr)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	u64 val64;
134462306a36Sopenharmony_ci	unsigned long flags;
134562306a36Sopenharmony_ci	u32 addrhi;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	spin_lock_irqsave(&oct->pci_win_lock, flags);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* The windowed read happens when the LSB of the addr is written.
135062306a36Sopenharmony_ci	 * So write MSB first
135162306a36Sopenharmony_ci	 */
135262306a36Sopenharmony_ci	addrhi = (addr >> 32);
135362306a36Sopenharmony_ci	if ((oct->chip_id == OCTEON_CN66XX) ||
135462306a36Sopenharmony_ci	    (oct->chip_id == OCTEON_CN68XX) ||
135562306a36Sopenharmony_ci	    (oct->chip_id == OCTEON_CN23XX_PF_VID))
135662306a36Sopenharmony_ci		addrhi |= 0x00060000;
135762306a36Sopenharmony_ci	writel(addrhi, oct->reg_list.pci_win_rd_addr_hi);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	/* Read back to preserve ordering of writes */
136062306a36Sopenharmony_ci	readl(oct->reg_list.pci_win_rd_addr_hi);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	writel(addr & 0xffffffff, oct->reg_list.pci_win_rd_addr_lo);
136362306a36Sopenharmony_ci	readl(oct->reg_list.pci_win_rd_addr_lo);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	val64 = readq(oct->reg_list.pci_win_rd_data);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	spin_unlock_irqrestore(&oct->pci_win_lock, flags);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return val64;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lio_pci_readq);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_civoid lio_pci_writeq(struct octeon_device *oct,
137462306a36Sopenharmony_ci		    u64 val,
137562306a36Sopenharmony_ci		    u64 addr)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	unsigned long flags;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	spin_lock_irqsave(&oct->pci_win_lock, flags);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	writeq(addr, oct->reg_list.pci_win_wr_addr);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	/* The write happens when the LSB is written. So write MSB first. */
138462306a36Sopenharmony_ci	writel(val >> 32, oct->reg_list.pci_win_wr_data_hi);
138562306a36Sopenharmony_ci	/* Read the MSB to ensure ordering of writes. */
138662306a36Sopenharmony_ci	readl(oct->reg_list.pci_win_wr_data_hi);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	writel(val & 0xffffffff, oct->reg_list.pci_win_wr_data_lo);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	spin_unlock_irqrestore(&oct->pci_win_lock, flags);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lio_pci_writeq);
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ciint octeon_mem_access_ok(struct octeon_device *oct)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	u64 access_okay = 0;
139762306a36Sopenharmony_ci	u64 lmc0_reset_ctl;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	/* Check to make sure a DDR interface is enabled */
140062306a36Sopenharmony_ci	if (OCTEON_CN23XX_PF(oct)) {
140162306a36Sopenharmony_ci		lmc0_reset_ctl = lio_pci_readq(oct, CN23XX_LMC0_RESET_CTL);
140262306a36Sopenharmony_ci		access_okay =
140362306a36Sopenharmony_ci			(lmc0_reset_ctl & CN23XX_LMC0_RESET_CTL_DDR3RST_MASK);
140462306a36Sopenharmony_ci	} else {
140562306a36Sopenharmony_ci		lmc0_reset_ctl = lio_pci_readq(oct, CN6XXX_LMC0_RESET_CTL);
140662306a36Sopenharmony_ci		access_okay =
140762306a36Sopenharmony_ci			(lmc0_reset_ctl & CN6XXX_LMC0_RESET_CTL_DDR3RST_MASK);
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	return access_okay ? 0 : 1;
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_mem_access_ok);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ciint octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	int ret = 1;
141762306a36Sopenharmony_ci	u32 ms;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (!timeout)
142062306a36Sopenharmony_ci		return ret;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	for (ms = 0; (ret != 0) && ((*timeout == 0) || (ms <= *timeout));
142362306a36Sopenharmony_ci	     ms += HZ / 10) {
142462306a36Sopenharmony_ci		ret = octeon_mem_access_ok(oct);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci		/* wait 100 ms */
142762306a36Sopenharmony_ci		if (ret)
142862306a36Sopenharmony_ci			schedule_timeout_uninterruptible(HZ / 10);
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	return ret;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(octeon_wait_for_ddr_init);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci/* Get the octeon id assigned to the octeon device passed as argument.
143662306a36Sopenharmony_ci *  This function is exported to other modules.
143762306a36Sopenharmony_ci *  @param dev - octeon device pointer passed as a void *.
143862306a36Sopenharmony_ci *  @return octeon device id
143962306a36Sopenharmony_ci */
144062306a36Sopenharmony_ciint lio_get_device_id(void *dev)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	struct octeon_device *octeon_dev = (struct octeon_device *)dev;
144362306a36Sopenharmony_ci	u32 i;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	for (i = 0; i < MAX_OCTEON_DEVICES; i++)
144662306a36Sopenharmony_ci		if (octeon_device[i] == octeon_dev)
144762306a36Sopenharmony_ci			return octeon_dev->octeon_id;
144862306a36Sopenharmony_ci	return -1;
144962306a36Sopenharmony_ci}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_civoid lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	u64 instr_cnt;
145462306a36Sopenharmony_ci	u32 pkts_pend;
145562306a36Sopenharmony_ci	struct octeon_device *oct = NULL;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	/* the whole thing needs to be atomic, ideally */
145862306a36Sopenharmony_ci	if (droq) {
145962306a36Sopenharmony_ci		pkts_pend = (u32)atomic_read(&droq->pkts_pending);
146062306a36Sopenharmony_ci		writel(droq->pkt_count - pkts_pend, droq->pkts_sent_reg);
146162306a36Sopenharmony_ci		droq->pkt_count = pkts_pend;
146262306a36Sopenharmony_ci		oct = droq->oct_dev;
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci	if (iq) {
146562306a36Sopenharmony_ci		spin_lock_bh(&iq->lock);
146662306a36Sopenharmony_ci		writel(iq->pkts_processed, iq->inst_cnt_reg);
146762306a36Sopenharmony_ci		iq->pkt_in_done -= iq->pkts_processed;
146862306a36Sopenharmony_ci		iq->pkts_processed = 0;
146962306a36Sopenharmony_ci		/* this write needs to be flushed before we release the lock */
147062306a36Sopenharmony_ci		spin_unlock_bh(&iq->lock);
147162306a36Sopenharmony_ci		oct = iq->oct_dev;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci	/*write resend. Writing RESEND in SLI_PKTX_CNTS should be enough
147462306a36Sopenharmony_ci	 *to trigger tx interrupts as well, if they are pending.
147562306a36Sopenharmony_ci	 */
147662306a36Sopenharmony_ci	if (oct && (OCTEON_CN23XX_PF(oct) || OCTEON_CN23XX_VF(oct))) {
147762306a36Sopenharmony_ci		if (droq)
147862306a36Sopenharmony_ci			writeq(CN23XX_INTR_RESEND, droq->pkts_sent_reg);
147962306a36Sopenharmony_ci		/*we race with firmrware here. read and write the IN_DONE_CNTS*/
148062306a36Sopenharmony_ci		else if (iq) {
148162306a36Sopenharmony_ci			instr_cnt =  readq(iq->inst_cnt_reg);
148262306a36Sopenharmony_ci			writeq(((instr_cnt & 0xFFFFFFFF00000000ULL) |
148362306a36Sopenharmony_ci				CN23XX_INTR_RESEND),
148462306a36Sopenharmony_ci			       iq->inst_cnt_reg);
148562306a36Sopenharmony_ci		}
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lio_enable_irq);
1489