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