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