1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * udbg debug output routine via GELIC UDP broadcasts
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2007 Sony Computer Entertainment Inc.
6*4882a593Smuzhiyun * Copyright 2006, 2007 Sony Corporation
7*4882a593Smuzhiyun * Copyright (C) 2010 Hector Martin <hector@marcansoft.com>
8*4882a593Smuzhiyun * Copyright (C) 2011 Andre Heider <a.heider@gmail.com>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/if_ether.h>
12*4882a593Smuzhiyun #include <linux/etherdevice.h>
13*4882a593Smuzhiyun #include <linux/if_vlan.h>
14*4882a593Smuzhiyun #include <linux/ip.h>
15*4882a593Smuzhiyun #include <linux/udp.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <asm/io.h>
18*4882a593Smuzhiyun #include <asm/udbg.h>
19*4882a593Smuzhiyun #include <asm/lv1call.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define GELIC_BUS_ID 1
22*4882a593Smuzhiyun #define GELIC_DEVICE_ID 0
23*4882a593Smuzhiyun #define GELIC_DEBUG_PORT 18194
24*4882a593Smuzhiyun #define GELIC_MAX_MESSAGE_SIZE 1000
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define GELIC_LV1_GET_MAC_ADDRESS 1
27*4882a593Smuzhiyun #define GELIC_LV1_GET_VLAN_ID 4
28*4882a593Smuzhiyun #define GELIC_LV1_VLAN_TX_ETHERNET_0 2
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define GELIC_DESCR_DMA_STAT_MASK 0xf0000000
31*4882a593Smuzhiyun #define GELIC_DESCR_DMA_CARDOWNED 0xa0000000
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define GELIC_DESCR_TX_DMA_IKE 0x00080000
34*4882a593Smuzhiyun #define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x00000000
35*4882a593Smuzhiyun #define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x00040000
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \
38*4882a593Smuzhiyun GELIC_DESCR_TX_DMA_IKE | \
39*4882a593Smuzhiyun GELIC_DESCR_TX_DMA_NO_CHKSUM)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun static u64 bus_addr;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun struct gelic_descr {
44*4882a593Smuzhiyun /* as defined by the hardware */
45*4882a593Smuzhiyun __be32 buf_addr;
46*4882a593Smuzhiyun __be32 buf_size;
47*4882a593Smuzhiyun __be32 next_descr_addr;
48*4882a593Smuzhiyun __be32 dmac_cmd_status;
49*4882a593Smuzhiyun __be32 result_size;
50*4882a593Smuzhiyun __be32 valid_size; /* all zeroes for tx */
51*4882a593Smuzhiyun __be32 data_status;
52*4882a593Smuzhiyun __be32 data_error; /* all zeroes for tx */
53*4882a593Smuzhiyun } __attribute__((aligned(32)));
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct debug_block {
56*4882a593Smuzhiyun struct gelic_descr descr;
57*4882a593Smuzhiyun u8 pkt[1520];
58*4882a593Smuzhiyun } __packed;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static __iomem struct ethhdr *h_eth;
61*4882a593Smuzhiyun static __iomem struct vlan_hdr *h_vlan;
62*4882a593Smuzhiyun static __iomem struct iphdr *h_ip;
63*4882a593Smuzhiyun static __iomem struct udphdr *h_udp;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static __iomem char *pmsg;
66*4882a593Smuzhiyun static __iomem char *pmsgc;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static __iomem struct debug_block dbg __attribute__((aligned(32)));
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static int header_size;
71*4882a593Smuzhiyun
map_dma_mem(int bus_id,int dev_id,void * start,size_t len,u64 * real_bus_addr)72*4882a593Smuzhiyun static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len,
73*4882a593Smuzhiyun u64 *real_bus_addr)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun s64 result;
76*4882a593Smuzhiyun u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL;
77*4882a593Smuzhiyun u64 real_end = real_addr + len;
78*4882a593Smuzhiyun u64 map_start = real_addr & ~0xfff;
79*4882a593Smuzhiyun u64 map_end = (real_end + 0xfff) & ~0xfff;
80*4882a593Smuzhiyun u64 bus_addr = 0;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun u64 flags = 0xf800000000000000UL;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun result = lv1_allocate_device_dma_region(bus_id, dev_id,
85*4882a593Smuzhiyun map_end - map_start, 12, 0,
86*4882a593Smuzhiyun &bus_addr);
87*4882a593Smuzhiyun if (result)
88*4882a593Smuzhiyun lv1_panic(0);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun result = lv1_map_device_dma_region(bus_id, dev_id, map_start,
91*4882a593Smuzhiyun bus_addr, map_end - map_start,
92*4882a593Smuzhiyun flags);
93*4882a593Smuzhiyun if (result)
94*4882a593Smuzhiyun lv1_panic(0);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun *real_bus_addr = bus_addr + real_addr - map_start;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
unmap_dma_mem(int bus_id,int dev_id,u64 bus_addr,size_t len)99*4882a593Smuzhiyun static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun s64 result;
102*4882a593Smuzhiyun u64 real_bus_addr;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun real_bus_addr = bus_addr & ~0xfff;
105*4882a593Smuzhiyun len += bus_addr - real_bus_addr;
106*4882a593Smuzhiyun len = (len + 0xfff) & ~0xfff;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr,
109*4882a593Smuzhiyun len);
110*4882a593Smuzhiyun if (result)
111*4882a593Smuzhiyun return result;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
gelic_debug_init(void)116*4882a593Smuzhiyun static void gelic_debug_init(void)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun s64 result;
119*4882a593Smuzhiyun u64 v2;
120*4882a593Smuzhiyun u64 mac;
121*4882a593Smuzhiyun u64 vlan_id;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0);
124*4882a593Smuzhiyun if (result)
125*4882a593Smuzhiyun lv1_panic(0);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg),
128*4882a593Smuzhiyun &bus_addr);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun memset(&dbg, 0, sizeof(dbg));
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun wmb();
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
137*4882a593Smuzhiyun GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0,
138*4882a593Smuzhiyun &mac, &v2);
139*4882a593Smuzhiyun if (result)
140*4882a593Smuzhiyun lv1_panic(0);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun mac <<= 16;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun h_eth = (struct ethhdr *)dbg.pkt;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun eth_broadcast_addr(h_eth->h_dest);
147*4882a593Smuzhiyun memcpy(&h_eth->h_source, &mac, ETH_ALEN);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun header_size = sizeof(struct ethhdr);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
152*4882a593Smuzhiyun GELIC_LV1_GET_VLAN_ID,
153*4882a593Smuzhiyun GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
154*4882a593Smuzhiyun &vlan_id, &v2);
155*4882a593Smuzhiyun if (!result) {
156*4882a593Smuzhiyun h_eth->h_proto= ETH_P_8021Q;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun header_size += sizeof(struct vlan_hdr);
159*4882a593Smuzhiyun h_vlan = (struct vlan_hdr *)(h_eth + 1);
160*4882a593Smuzhiyun h_vlan->h_vlan_TCI = vlan_id;
161*4882a593Smuzhiyun h_vlan->h_vlan_encapsulated_proto = ETH_P_IP;
162*4882a593Smuzhiyun h_ip = (struct iphdr *)(h_vlan + 1);
163*4882a593Smuzhiyun } else {
164*4882a593Smuzhiyun h_eth->h_proto= 0x0800;
165*4882a593Smuzhiyun h_ip = (struct iphdr *)(h_eth + 1);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun header_size += sizeof(struct iphdr);
169*4882a593Smuzhiyun h_ip->version = 4;
170*4882a593Smuzhiyun h_ip->ihl = 5;
171*4882a593Smuzhiyun h_ip->ttl = 10;
172*4882a593Smuzhiyun h_ip->protocol = 0x11;
173*4882a593Smuzhiyun h_ip->saddr = 0x00000000;
174*4882a593Smuzhiyun h_ip->daddr = 0xffffffff;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun header_size += sizeof(struct udphdr);
177*4882a593Smuzhiyun h_udp = (struct udphdr *)(h_ip + 1);
178*4882a593Smuzhiyun h_udp->source = GELIC_DEBUG_PORT;
179*4882a593Smuzhiyun h_udp->dest = GELIC_DEBUG_PORT;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun pmsgc = pmsg = (char *)(h_udp + 1);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
gelic_debug_shutdown(void)184*4882a593Smuzhiyun static void gelic_debug_shutdown(void)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun if (bus_addr)
187*4882a593Smuzhiyun unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID,
188*4882a593Smuzhiyun bus_addr, sizeof(dbg));
189*4882a593Smuzhiyun lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
gelic_sendbuf(int msgsize)192*4882a593Smuzhiyun static void gelic_sendbuf(int msgsize)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun u16 *p;
195*4882a593Smuzhiyun u32 sum;
196*4882a593Smuzhiyun int i;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun dbg.descr.buf_size = header_size + msgsize;
199*4882a593Smuzhiyun h_ip->tot_len = msgsize + sizeof(struct udphdr) +
200*4882a593Smuzhiyun sizeof(struct iphdr);
201*4882a593Smuzhiyun h_udp->len = msgsize + sizeof(struct udphdr);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun h_ip->check = 0;
204*4882a593Smuzhiyun sum = 0;
205*4882a593Smuzhiyun p = (u16 *)h_ip;
206*4882a593Smuzhiyun for (i = 0; i < 5; i++)
207*4882a593Smuzhiyun sum += *p++;
208*4882a593Smuzhiyun h_ip->check = ~(sum + (sum >> 16));
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM |
211*4882a593Smuzhiyun GELIC_DESCR_TX_DMA_FRAME_TAIL;
212*4882a593Smuzhiyun dbg.descr.result_size = 0;
213*4882a593Smuzhiyun dbg.descr.data_status = 0;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun wmb();
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) ==
220*4882a593Smuzhiyun GELIC_DESCR_DMA_CARDOWNED)
221*4882a593Smuzhiyun cpu_relax();
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
ps3gelic_udbg_putc(char ch)224*4882a593Smuzhiyun static void ps3gelic_udbg_putc(char ch)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun *pmsgc++ = ch;
227*4882a593Smuzhiyun if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) {
228*4882a593Smuzhiyun gelic_sendbuf(pmsgc-pmsg);
229*4882a593Smuzhiyun pmsgc = pmsg;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
udbg_init_ps3gelic(void)233*4882a593Smuzhiyun void __init udbg_init_ps3gelic(void)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun gelic_debug_init();
236*4882a593Smuzhiyun udbg_putc = ps3gelic_udbg_putc;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
udbg_shutdown_ps3gelic(void)239*4882a593Smuzhiyun void udbg_shutdown_ps3gelic(void)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun udbg_putc = NULL;
242*4882a593Smuzhiyun gelic_debug_shutdown();
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun EXPORT_SYMBOL(udbg_shutdown_ps3gelic);
245