27#include "../switchtec_priv.h"
31#include <linux/switchtec_ioctl.h>
42#include <sys/sysmacros.h>
46#include <sys/socket.h>
53#define ETH_SERVER_PORT 54545
55#define ETH_CHAN_TYPE_COMMAND 0x1
56#define ETH_CHAN_TYPE_EVENT 0x2
58#define ETH_PROT_SIGNATURE 0x6d6c7373
59#define ETH_PROT_VERSION 0x1
61#define ETH_PACKET_TYPE_OPEN 0xB1
62#define ETH_PACKET_TYPE_CMD 0xB2
64#define ETH_FUNC_TYPE_OPEN_REQUEST 0x1
65#define ETH_FUNC_TYPE_OPEN_ACCEPT 0x2
66#define ETH_FUNC_TYPE_OPEN_REJECT 0x3
67#define ETH_FUNC_TYPE_OPEN_CLOSE 0x4
69#define ETH_FUNC_TYPE_MRPC_CMD 0x1
70#define ETH_FUNC_TYPE_MOE_CMD 0x2
71#define ETH_FUNC_TYPE_MRPC_RESP 0x3
72#define ETH_FUNC_TYPE_EVENT 0x4
73#define ETH_FUNC_TYPE_MOE_RESP 0x5
75#define ETH_INST_ID_0 0x0
76#define ETH_INST_ID_1 0x1
78#define ETH_GAS_READ_CMD_ID 0x1001
79#define ETH_GAS_WRITE_CMD_ID 0x1002
81#define ETH_MAX_READ 512
84 struct switchtec_dev dev;
89#define to_switchtec_eth(d) \
90 ((struct switchtec_eth *) \
91 ((char *)d - offsetof(struct switchtec_eth, dev)))
97 uint8_t function_type;
100 uint8_t service_inst;
104 uint8_t service_type;
107 uint16_t payload_bytes;
109 uint16_t mrpc_output_bytes;
110 uint16_t return_code;
116 struct eth_header hdr;
117 uint8_t body[MRPC_MAX_DATA_LEN + 4];
120static int send_eth_command(
int cmd_fd,
int func_type, uint8_t *data,
121 uint32_t data_len, uint32_t mrpc_output_len)
124 struct eth_packet *command_p;
126 packet_len = offsetof(
struct eth_packet, body) + data_len;
127 command_p = malloc(packet_len);
131 command_p->hdr.signature = htonl(ETH_PROT_SIGNATURE);
132 command_p->hdr.version_id = ETH_PROT_VERSION;
133 command_p->hdr.function_type = func_type;
134 command_p->hdr.packet_type = ETH_PACKET_TYPE_CMD;
135 command_p->hdr.payload_bytes = htons(data_len);
136 command_p->hdr.mrpc_output_bytes = htons(mrpc_output_len);
138 memcpy(command_p->body, data, data_len);
140 if (send(cmd_fd, command_p, packet_len, 0) < 0) {
149static int recv_eth_response(
int cmd_fd, uint32_t *result,
150 uint8_t *output, uint32_t *output_len)
152 struct eth_packet recvd_p;
156 uint16_t packet_type;
158 len =
sizeof(
struct eth_header);
160 if (recv(cmd_fd, &recvd_p.hdr, len, 0) < 0)
163 func_type = recvd_p.hdr.function_type;
164 packet_type = recvd_p.hdr.packet_type;
166 if ((func_type == ETH_FUNC_TYPE_OPEN_CLOSE)
167 && (packet_type == ETH_PACKET_TYPE_OPEN))
170 len = ntohs(recvd_p.hdr.payload_bytes);
176 if (recv(cmd_fd, p, len, 0) < 0)
179 if (packet_type == ETH_PACKET_TYPE_CMD) {
180 *result = le32toh(*(uint32_t *)p);
181 p +=
sizeof(uint32_t);
182 len -=
sizeof(uint32_t);
184 memcpy(output, p, len);
192static int switchtec_submit_cmd_eth(
struct switchtec_dev *dev, uint32_t cmd,
193 const void *payload,
size_t payload_len,
196 struct switchtec_eth *edev = to_switchtec_eth(dev);
200 struct eth_mrpc_body{
203 } __attribute__(( packed )) *mrpc_body;
205 body_len = offsetof(
struct eth_mrpc_body, data) + payload_len;
206 mrpc_body = malloc(body_len);
209 memset(mrpc_body, 0, body_len);
211 mrpc_body->command_id = htole32(cmd);
212 memcpy(mrpc_body->data, payload, payload_len);
214 ret = send_eth_command(edev->cmd_fd, ETH_FUNC_TYPE_MRPC_CMD,
215 (uint8_t *)mrpc_body, body_len, resp_len);
221static int switchtec_read_resp_eth(
struct switchtec_dev *dev,
void *resp,
224 struct switchtec_eth *edev = to_switchtec_eth(dev);
227 uint8_t buf[resp_len];
228 uint32_t received_len;
230 ret = recv_eth_response(edev->cmd_fd, &result, buf, &received_len);
234 if (received_len != resp_len) {
245 memcpy(resp, buf, resp_len);
250static int eth_cmd(
struct switchtec_dev *dev, uint32_t cmd,
251 const void *payload,
size_t payload_len,
252 void *resp,
size_t resp_len)
256 ret = switchtec_submit_cmd_eth(dev, cmd, payload,
257 payload_len, resp_len);
262 return switchtec_read_resp_eth(dev, resp, resp_len);
266#define __force __attribute__((force))
271static int eth_gas_write_exec(
int fd, uint32_t offset,
272 const void *data, uint16_t bytes)
278 struct eth_gas_write_body{
284 } __attribute__(( packed )) *gas_write_body;
286 body_len = offsetof(
struct eth_gas_write_body, data) + bytes;
287 gas_write_body = malloc(body_len);
290 memset(gas_write_body, 0, body_len);
292 gas_write_body->command_id = htole32(ETH_GAS_WRITE_CMD_ID);
293 gas_write_body->offset = htole32(offset);
294 gas_write_body->bytes = htole16(bytes);
296 memcpy(gas_write_body->data, data, bytes);
298 ret = send_eth_command(fd, ETH_FUNC_TYPE_MOE_CMD,
299 (uint8_t *)gas_write_body, body_len, 0);
301 free(gas_write_body);
306 ret = recv_eth_response(fd, &result, NULL, NULL);
311static int eth_gas_read_exec(
struct switchtec_dev *dev, uint32_t offset,
312 uint8_t *data,
size_t bytes)
314 struct switchtec_eth *edev = to_switchtec_eth(dev);
320 struct eth_gas_write_body{
325 } __attribute__(( packed )) gas_read_body;
327 gas_read_body.command_id = htole32(ETH_GAS_READ_CMD_ID);
328 gas_read_body.offset = htole32(offset);
329 gas_read_body.bytes = htole16(bytes);
331 body_len =
sizeof(gas_read_body);
333 ret = send_eth_command(edev->cmd_fd, ETH_FUNC_TYPE_MOE_CMD,
334 (uint8_t *)&gas_read_body, body_len, 0);
339 ret = recv_eth_response(edev->cmd_fd, &result, data, &data_len);
344static void eth_gas_read(
struct switchtec_dev *dev,
void *dest,
345 const void __gas *src,
size_t n)
350 gas_addr = (uint32_t)(src - (
void __gas *)dev->gas_map);
351 ret = eth_gas_read_exec(dev, gas_addr, dest, n);
356static void eth_gas_write(
struct switchtec_dev *dev,
void __gas *dest,
357 const void *src,
size_t n)
360 struct switchtec_eth *edev = to_switchtec_eth(dev);
363 gas_addr = (uint32_t)(dest - (
void __gas *)dev->gas_map);
364 ret = eth_gas_write_exec(edev->cmd_fd, gas_addr, src, n);
369static void eth_gas_write8(
struct switchtec_dev *dev, uint8_t val,
372 eth_gas_write(dev, addr, &val,
sizeof(uint8_t));
375static void eth_gas_write16(
struct switchtec_dev *dev, uint16_t val,
376 uint16_t __gas *addr)
379 eth_gas_write(dev, addr, &val,
sizeof(uint16_t));
382static void eth_gas_write32(
struct switchtec_dev *dev, uint32_t val,
383 uint32_t __gas *addr)
386 eth_gas_write(dev, addr, &val,
sizeof(uint32_t));
389static void eth_gas_write64(
struct switchtec_dev *dev, uint64_t val,
390 uint64_t __gas *addr)
393 eth_gas_write(dev, addr, &val,
sizeof(uint64_t));
396static void eth_memcpy_from_gas(
struct switchtec_dev *dev,
void *dest,
397 const void __gas *src,
size_t n)
399 eth_gas_read(dev, dest, src, n);
402static void eth_memcpy_to_gas(
struct switchtec_dev *dev,
void __gas *dest,
403 const void *src,
size_t n)
405 eth_gas_write(dev, dest, src, n);
408static ssize_t eth_write_from_gas(
struct switchtec_dev *dev,
int fd,
409 const void __gas *src,
size_t n)
412 uint8_t buf[ETH_MAX_READ];
416 cnt = n > ETH_MAX_READ ? ETH_MAX_READ : n;
417 eth_memcpy_from_gas(dev, buf, src, cnt);
418 ret += write(fd, buf, cnt);
427static uint8_t eth_gas_read8(
struct switchtec_dev *dev, uint8_t __gas *addr)
431 eth_gas_read(dev, &val, addr,
sizeof(val));
435static uint16_t eth_gas_read16(
struct switchtec_dev *dev, uint16_t __gas *addr)
439 eth_gas_read(dev, &val, addr,
sizeof(val));
443static uint32_t eth_gas_read32(
struct switchtec_dev *dev, uint32_t __gas *addr)
447 eth_gas_read(dev, &val, addr,
sizeof(val));
451static uint64_t eth_gas_read64(
struct switchtec_dev *dev, uint64_t __gas *addr)
455 eth_gas_read(dev, &val, addr,
sizeof(val));
459static void eth_close(
struct switchtec_dev *dev)
461 struct switchtec_eth *edev = to_switchtec_eth(dev);
464 munmap((
void __force *)dev->gas_map, dev->gas_map_size);
470static int map_gas(
struct switchtec_dev *dev)
473 dev->gas_map_size = 4 << 20;
484 addr = mmap(NULL, dev->gas_map_size, PROT_NONE,
485 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
486 if (addr == MAP_FAILED)
489 dev->gas_map = (
gasptr_t __force)addr;
494static gasptr_t eth_gas_map(
struct switchtec_dev *dev,
int writeable,
498 *map_size = dev->gas_map_size;
503static int eth_event_wait(
struct switchtec_dev *dev,
int timeout_ms)
506 struct eth_packet recvd_p;
507 struct switchtec_eth *edev = to_switchtec_eth(dev);
510 len =
sizeof(
struct eth_header);
512 if (timeout_ms != -1)
513 setsockopt(edev->evt_fd, SOL_SOCKET, SO_RCVTIMEO,
514 (
char *)&timeout_ms,
sizeof(
int));
516 ret = recv(edev->evt_fd, &recvd_p.hdr, len, 0);
520 if ((recvd_p.hdr.packet_type == ETH_PACKET_TYPE_CMD)
521 && (recvd_p.hdr.function_type == ETH_FUNC_TYPE_EVENT))
527static const struct switchtec_ops eth_ops = {
529 .gas_map = eth_gas_map,
531 .get_device_id = gasop_get_device_id,
532 .get_fw_version = gasop_get_fw_version,
533 .get_device_version = gasop_get_device_version,
534 .pff_to_port = gasop_pff_to_port,
535 .port_to_pff = gasop_port_to_pff,
536 .flash_part = gasop_flash_part,
537 .event_summary = gasop_event_summary,
538 .event_ctl = gasop_event_ctl,
539 .event_wait = eth_event_wait,
541 .gas_read8 = eth_gas_read8,
542 .gas_read16 = eth_gas_read16,
543 .gas_read32 = eth_gas_read32,
544 .gas_read64 = eth_gas_read64,
545 .gas_write8 = eth_gas_write8,
546 .gas_write16 = eth_gas_write16,
547 .gas_write32 = eth_gas_write32,
548 .gas_write32_no_retry = eth_gas_write32,
549 .gas_write64 = eth_gas_write64,
550 .memcpy_to_gas = eth_memcpy_to_gas,
551 .memcpy_from_gas = eth_memcpy_from_gas,
552 .write_from_gas = eth_write_from_gas,
555static int open_eth_chan(
const char *server_ip,
int server_port,
556 int chan_type,
int moe_inst_id)
559 struct eth_packet *open_p;
561 struct sockaddr_in server;
565 fd = socket(AF_INET, SOCK_STREAM, 0);
570 server.sin_addr.s_addr = inet_addr(server_ip);
571 server.sin_family = AF_INET;
572 server.sin_port = htons(server_port);
574 if (connect(fd, (
struct sockaddr *)&server ,
sizeof(server)) < 0) {
579 len =
sizeof(
struct eth_header);
581 open_p = malloc(
sizeof(
struct eth_packet));
587 open_p->hdr.signature = htonl(ETH_PROT_SIGNATURE);
588 open_p->hdr.version_id = ETH_PROT_VERSION;
589 open_p->hdr.function_type = ETH_FUNC_TYPE_OPEN_REQUEST;
590 open_p->hdr.packet_type = ETH_PACKET_TYPE_OPEN;
591 open_p->hdr.service_inst = moe_inst_id;
592 open_p->hdr.service_type = chan_type;
594 if (send(fd, open_p, len, 0) < 0) {
599 len =
sizeof(
struct eth_header);
600 if (recv(fd, open_p, len, 0) < 0) {
605 if (!((open_p->hdr.function_type == ETH_FUNC_TYPE_OPEN_ACCEPT)
606 && (open_p->hdr.return_code == 0)))
616 struct switchtec_eth *edev;
618 edev = malloc(
sizeof(*edev));
622 edev->cmd_fd = open_eth_chan(ip, ETH_SERVER_PORT,
623 ETH_CHAN_TYPE_COMMAND, inst);
624 if (edev->cmd_fd < 0)
625 goto err_close_cmd_free;
627 edev->evt_fd = open_eth_chan(ip, ETH_SERVER_PORT,
628 ETH_CHAN_TYPE_EVENT, inst);
629 if (edev->evt_fd < 0)
632 if (map_gas(&edev->dev))
635 edev->dev.ops = ð_ops;
637 gasop_set_partition_info(&edev->dev);
struct switchtec_dev * switchtec_open_eth(const char *ip, const int inst)
Open a switchtec device over ethernet.
__gas struct switchtec_gas * gasptr_t
Shortform for a pointer to the GAS register space.