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