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
1762306a36Sopenharmony_ci * details.
1862306a36Sopenharmony_ci **********************************************************************/
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*!  \file octeon_nic.h
2162306a36Sopenharmony_ci *   \brief Host NIC Driver: Routine to send network data &
2262306a36Sopenharmony_ci *   control packet to Octeon.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifndef __OCTEON_NIC_H__
2662306a36Sopenharmony_ci#define  __OCTEON_NIC_H__
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Maximum number of 8-byte words can be sent in a NIC control message.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define  MAX_NCTRL_UDD  32
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_citypedef void (*octnic_ctrl_pkt_cb_fn_t) (void *);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Structure of control information passed by the NIC module to the OSI
3562306a36Sopenharmony_ci * layer when sending control commands to Octeon device software.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistruct octnic_ctrl_pkt {
3862306a36Sopenharmony_ci	/** Command to be passed to the Octeon device software. */
3962306a36Sopenharmony_ci	union octnet_cmd ncmd;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/** Send buffer  */
4262306a36Sopenharmony_ci	void *data;
4362306a36Sopenharmony_ci	u64 dmadata;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/** Response buffer */
4662306a36Sopenharmony_ci	void *rdata;
4762306a36Sopenharmony_ci	u64 dmardata;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/** Additional data that may be needed by some commands. */
5062306a36Sopenharmony_ci	u64 udd[MAX_NCTRL_UDD];
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/** Input queue to use to send this command. */
5362306a36Sopenharmony_ci	u64 iq_no;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/** The network device that issued the control command. */
5662306a36Sopenharmony_ci	u64 netpndev;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/** Callback function called when the command has been fetched */
5962306a36Sopenharmony_ci	octnic_ctrl_pkt_cb_fn_t cb_fn;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	u32 sc_status;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define MAX_UDD_SIZE(nctrl) (sizeof((nctrl)->udd))
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/** Structure of data information passed by the NIC module to the OSI
6762306a36Sopenharmony_ci * layer when forwarding data to Octeon device software.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistruct octnic_data_pkt {
7062306a36Sopenharmony_ci	/** Pointer to information maintained by NIC module for this packet. The
7162306a36Sopenharmony_ci	 *  OSI layer passes this as-is to the driver.
7262306a36Sopenharmony_ci	 */
7362306a36Sopenharmony_ci	void *buf;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/** Type of buffer passed in "buf" above. */
7662306a36Sopenharmony_ci	u32 reqtype;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/** Total data bytes to be transferred in this command. */
7962306a36Sopenharmony_ci	u32 datasize;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/** Command to be passed to the Octeon device software. */
8262306a36Sopenharmony_ci	union octeon_instr_64B cmd;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/** Input queue to use to send this command. */
8562306a36Sopenharmony_ci	u32 q_no;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/** Structure passed by NIC module to OSI layer to prepare a command to send
9062306a36Sopenharmony_ci * network data to Octeon.
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_ciunion octnic_cmd_setup {
9362306a36Sopenharmony_ci	struct {
9462306a36Sopenharmony_ci		u32 iq_no:8;
9562306a36Sopenharmony_ci		u32 gather:1;
9662306a36Sopenharmony_ci		u32 timestamp:1;
9762306a36Sopenharmony_ci		u32 ip_csum:1;
9862306a36Sopenharmony_ci		u32 transport_csum:1;
9962306a36Sopenharmony_ci		u32 tnl_csum:1;
10062306a36Sopenharmony_ci		u32 rsvd:19;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		union {
10362306a36Sopenharmony_ci			u32 datasize;
10462306a36Sopenharmony_ci			u32 gatherptrs;
10562306a36Sopenharmony_ci		} u;
10662306a36Sopenharmony_ci	} s;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	u64 u64;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic inline int octnet_iq_is_full(struct octeon_device *oct, u32 q_no)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	return ((u32)atomic_read(&oct->instr_queue[q_no]->instr_pending)
11562306a36Sopenharmony_ci		>= (oct->instr_queue[q_no]->max_count - 2));
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline void
11962306a36Sopenharmony_cioctnet_prepare_pci_cmd_o2(struct octeon_device *oct,
12062306a36Sopenharmony_ci			  union octeon_instr_64B *cmd,
12162306a36Sopenharmony_ci			  union octnic_cmd_setup *setup, u32 tag)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct octeon_instr_ih2 *ih2;
12462306a36Sopenharmony_ci	struct octeon_instr_irh *irh;
12562306a36Sopenharmony_ci	union octnic_packet_params packet_params;
12662306a36Sopenharmony_ci	int port;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	memset(cmd, 0, sizeof(union octeon_instr_64B));
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	ih2 = (struct octeon_instr_ih2 *)&cmd->cmd2.ih2;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* assume that rflag is cleared so therefore front data will only have
13362306a36Sopenharmony_ci	 * irh and ossp[0], ossp[1] for a total of 32 bytes
13462306a36Sopenharmony_ci	 */
13562306a36Sopenharmony_ci	ih2->fsz = LIO_PCICMD_O2;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	ih2->tagtype = ORDERED_TAG;
13862306a36Sopenharmony_ci	ih2->grp = DEFAULT_POW_GRP;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	port = (int)oct->instr_queue[setup->s.iq_no]->txpciq.s.port;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (tag)
14362306a36Sopenharmony_ci		ih2->tag = tag;
14462306a36Sopenharmony_ci	else
14562306a36Sopenharmony_ci		ih2->tag = LIO_DATA(port);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	ih2->raw = 1;
14862306a36Sopenharmony_ci	ih2->qos = (port & 3) + 4;	/* map qos based on interface */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (!setup->s.gather) {
15162306a36Sopenharmony_ci		ih2->dlengsz = setup->s.u.datasize;
15262306a36Sopenharmony_ci	} else {
15362306a36Sopenharmony_ci		ih2->gather = 1;
15462306a36Sopenharmony_ci		ih2->dlengsz = setup->s.u.gatherptrs;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	irh = (struct octeon_instr_irh *)&cmd->cmd2.irh;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	irh->opcode = OPCODE_NIC;
16062306a36Sopenharmony_ci	irh->subcode = OPCODE_NIC_NW_DATA;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	packet_params.u32 = 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	packet_params.s.ip_csum = setup->s.ip_csum;
16562306a36Sopenharmony_ci	packet_params.s.transport_csum = setup->s.transport_csum;
16662306a36Sopenharmony_ci	packet_params.s.tnl_csum = setup->s.tnl_csum;
16762306a36Sopenharmony_ci	packet_params.s.tsflag = setup->s.timestamp;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	irh->ossp = packet_params.u32;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic inline void
17362306a36Sopenharmony_cioctnet_prepare_pci_cmd_o3(struct octeon_device *oct,
17462306a36Sopenharmony_ci			  union octeon_instr_64B *cmd,
17562306a36Sopenharmony_ci			  union octnic_cmd_setup *setup, u32 tag)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct octeon_instr_irh *irh;
17862306a36Sopenharmony_ci	struct octeon_instr_ih3     *ih3;
17962306a36Sopenharmony_ci	struct octeon_instr_pki_ih3 *pki_ih3;
18062306a36Sopenharmony_ci	union octnic_packet_params packet_params;
18162306a36Sopenharmony_ci	int port;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	memset(cmd, 0, sizeof(union octeon_instr_64B));
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ih3 = (struct octeon_instr_ih3 *)&cmd->cmd3.ih3;
18662306a36Sopenharmony_ci	pki_ih3 = (struct octeon_instr_pki_ih3 *)&cmd->cmd3.pki_ih3;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* assume that rflag is cleared so therefore front data will only have
18962306a36Sopenharmony_ci	 * irh and ossp[1] and ossp[2] for a total of 24 bytes
19062306a36Sopenharmony_ci	 */
19162306a36Sopenharmony_ci	ih3->pkind       = oct->instr_queue[setup->s.iq_no]->txpciq.s.pkind;
19262306a36Sopenharmony_ci	/*PKI IH*/
19362306a36Sopenharmony_ci	ih3->fsz = LIO_PCICMD_O3;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (!setup->s.gather) {
19662306a36Sopenharmony_ci		ih3->dlengsz = setup->s.u.datasize;
19762306a36Sopenharmony_ci	} else {
19862306a36Sopenharmony_ci		ih3->gather = 1;
19962306a36Sopenharmony_ci		ih3->dlengsz = setup->s.u.gatherptrs;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	pki_ih3->w       = 1;
20362306a36Sopenharmony_ci	pki_ih3->raw     = 1;
20462306a36Sopenharmony_ci	pki_ih3->utag    = 1;
20562306a36Sopenharmony_ci	pki_ih3->utt     = 1;
20662306a36Sopenharmony_ci	pki_ih3->uqpg    = oct->instr_queue[setup->s.iq_no]->txpciq.s.use_qpg;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	port = (int)oct->instr_queue[setup->s.iq_no]->txpciq.s.port;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (tag)
21162306a36Sopenharmony_ci		pki_ih3->tag = tag;
21262306a36Sopenharmony_ci	else
21362306a36Sopenharmony_ci		pki_ih3->tag     = LIO_DATA(port);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	pki_ih3->tagtype = ORDERED_TAG;
21662306a36Sopenharmony_ci	pki_ih3->qpg     = oct->instr_queue[setup->s.iq_no]->txpciq.s.qpg;
21762306a36Sopenharmony_ci	pki_ih3->pm      = 0x7; /*0x7 - meant for Parse nothing, uninterpreted*/
21862306a36Sopenharmony_ci	pki_ih3->sl      = 8;   /* sl will be sizeof(pki_ih3)*/
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	irh = (struct octeon_instr_irh *)&cmd->cmd3.irh;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	irh->opcode = OPCODE_NIC;
22362306a36Sopenharmony_ci	irh->subcode = OPCODE_NIC_NW_DATA;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	packet_params.u32 = 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	packet_params.s.ip_csum = setup->s.ip_csum;
22862306a36Sopenharmony_ci	packet_params.s.transport_csum = setup->s.transport_csum;
22962306a36Sopenharmony_ci	packet_params.s.tnl_csum = setup->s.tnl_csum;
23062306a36Sopenharmony_ci	packet_params.s.tsflag = setup->s.timestamp;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	irh->ossp = packet_params.u32;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/** Utility function to prepare a 64B NIC instruction based on a setup command
23662306a36Sopenharmony_ci * @param cmd - pointer to instruction to be filled in.
23762306a36Sopenharmony_ci * @param setup - pointer to the setup structure
23862306a36Sopenharmony_ci * @param q_no - which queue for back pressure
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * Assumes the cmd instruction is pre-allocated, but no fields are filled in.
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_cistatic inline void
24362306a36Sopenharmony_cioctnet_prepare_pci_cmd(struct octeon_device *oct, union octeon_instr_64B *cmd,
24462306a36Sopenharmony_ci		       union octnic_cmd_setup *setup, u32 tag)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	if (OCTEON_CN6XXX(oct))
24762306a36Sopenharmony_ci		octnet_prepare_pci_cmd_o2(oct, cmd, setup, tag);
24862306a36Sopenharmony_ci	else
24962306a36Sopenharmony_ci		octnet_prepare_pci_cmd_o3(oct, cmd, setup, tag);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/** Allocate and a soft command with space for a response immediately following
25362306a36Sopenharmony_ci * the commnad.
25462306a36Sopenharmony_ci * @param oct - octeon device pointer
25562306a36Sopenharmony_ci * @param cmd - pointer to the command structure, pre-filled for everything
25662306a36Sopenharmony_ci * except the response.
25762306a36Sopenharmony_ci * @param rdatasize - size in bytes of the response.
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * @returns pointer to allocated buffer with command copied into it, and
26062306a36Sopenharmony_ci * response space immediately following.
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_civoid *
26362306a36Sopenharmony_ciocteon_alloc_soft_command_resp(struct octeon_device    *oct,
26462306a36Sopenharmony_ci			       union octeon_instr_64B *cmd,
26562306a36Sopenharmony_ci			       u32		       rdatasize);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/** Send a NIC data packet to the device
26862306a36Sopenharmony_ci * @param oct - octeon device pointer
26962306a36Sopenharmony_ci * @param ndata - control structure with queueing, and buffer information
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * @returns IQ_FAILED if it failed to add to the input queue. IQ_STOP if it the
27262306a36Sopenharmony_ci * queue should be stopped, and IQ_SEND_OK if it sent okay.
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_ciint octnet_send_nic_data_pkt(struct octeon_device *oct,
27562306a36Sopenharmony_ci			     struct octnic_data_pkt *ndata,
27662306a36Sopenharmony_ci			     int xmit_more);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/** Send a NIC control packet to the device
27962306a36Sopenharmony_ci * @param oct - octeon device pointer
28062306a36Sopenharmony_ci * @param nctrl - control structure with command, timout, and callback info
28162306a36Sopenharmony_ci * @returns IQ_FAILED if it failed to add to the input queue. IQ_STOP if it the
28262306a36Sopenharmony_ci * queue should be stopped, and IQ_SEND_OK if it sent okay.
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_ciint
28562306a36Sopenharmony_cioctnet_send_nic_ctrl_pkt(struct octeon_device *oct,
28662306a36Sopenharmony_ci			 struct octnic_ctrl_pkt *nctrl);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci#endif
289