Path: blob/master/arch/powerpc/platforms/ps3/gelic_udbg.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* udbg debug output routine via GELIC UDP broadcasts3*4* Copyright (C) 2007 Sony Computer Entertainment Inc.5* Copyright 2006, 2007 Sony Corporation6* Copyright (C) 2010 Hector Martin <[email protected]>7* Copyright (C) 2011 Andre Heider <[email protected]>8*/910#include <linux/if_ether.h>11#include <linux/etherdevice.h>12#include <linux/if_vlan.h>13#include <linux/ip.h>14#include <linux/udp.h>1516#include <asm/ps3.h>17#include <asm/io.h>18#include <asm/udbg.h>19#include <asm/lv1call.h>2021#define GELIC_BUS_ID 122#define GELIC_DEVICE_ID 023#define GELIC_DEBUG_PORT 1819424#define GELIC_MAX_MESSAGE_SIZE 10002526#define GELIC_LV1_GET_MAC_ADDRESS 127#define GELIC_LV1_GET_VLAN_ID 428#define GELIC_LV1_VLAN_TX_ETHERNET_0 22930#define GELIC_DESCR_DMA_STAT_MASK 0xf000000031#define GELIC_DESCR_DMA_CARDOWNED 0xa00000003233#define GELIC_DESCR_TX_DMA_IKE 0x0008000034#define GELIC_DESCR_TX_DMA_NO_CHKSUM 0x0000000035#define GELIC_DESCR_TX_DMA_FRAME_TAIL 0x000400003637#define GELIC_DESCR_DMA_CMD_NO_CHKSUM (GELIC_DESCR_DMA_CARDOWNED | \38GELIC_DESCR_TX_DMA_IKE | \39GELIC_DESCR_TX_DMA_NO_CHKSUM)4041static u64 bus_addr;4243struct 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)));5455struct debug_block {56struct gelic_descr descr;57u8 pkt[1520];58} __packed;5960static __iomem struct ethhdr *h_eth;61static __iomem struct vlan_hdr *h_vlan;62static __iomem struct iphdr *h_ip;63static __iomem struct udphdr *h_udp;6465static __iomem char *pmsg;66static __iomem char *pmsgc;6768static __iomem struct debug_block dbg __attribute__((aligned(32)));6970static int header_size;7172static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len,73u64 *real_bus_addr)74{75s64 result;76u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL;77u64 real_end = real_addr + len;78u64 map_start = real_addr & ~0xfff;79u64 map_end = (real_end + 0xfff) & ~0xfff;80u64 bus_addr = 0;8182u64 flags = 0xf800000000000000UL;8384result = lv1_allocate_device_dma_region(bus_id, dev_id,85map_end - map_start, 12, 0,86&bus_addr);87if (result)88lv1_panic(0);8990result = lv1_map_device_dma_region(bus_id, dev_id, map_start,91bus_addr, map_end - map_start,92flags);93if (result)94lv1_panic(0);9596*real_bus_addr = bus_addr + real_addr - map_start;97}9899static int unmap_dma_mem(int bus_id, int dev_id, u64 bus_addr, size_t len)100{101s64 result;102u64 real_bus_addr;103104real_bus_addr = bus_addr & ~0xfff;105len += bus_addr - real_bus_addr;106len = (len + 0xfff) & ~0xfff;107108result = lv1_unmap_device_dma_region(bus_id, dev_id, real_bus_addr,109len);110if (result)111return result;112113return lv1_free_device_dma_region(bus_id, dev_id, real_bus_addr);114}115116static void __init gelic_debug_init(void)117{118s64 result;119u64 v2;120u64 mac;121u64 vlan_id;122123result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0);124if (result)125lv1_panic(0);126127map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg),128&bus_addr);129130memset(&dbg, 0, sizeof(dbg));131132dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt);133134wmb();135136result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,137GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0,138&mac, &v2);139if (result)140lv1_panic(0);141142mac <<= 16;143144h_eth = (struct ethhdr *)dbg.pkt;145146eth_broadcast_addr(h_eth->h_dest);147memcpy(&h_eth->h_source, &mac, ETH_ALEN);148149header_size = sizeof(struct ethhdr);150151result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,152GELIC_LV1_GET_VLAN_ID,153GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,154&vlan_id, &v2);155if (!result) {156h_eth->h_proto= ETH_P_8021Q;157158header_size += sizeof(struct vlan_hdr);159h_vlan = (struct vlan_hdr *)(h_eth + 1);160h_vlan->h_vlan_TCI = vlan_id;161h_vlan->h_vlan_encapsulated_proto = ETH_P_IP;162h_ip = (struct iphdr *)(h_vlan + 1);163} else {164h_eth->h_proto= 0x0800;165h_ip = (struct iphdr *)(h_eth + 1);166}167168header_size += sizeof(struct iphdr);169h_ip->version = 4;170h_ip->ihl = 5;171h_ip->ttl = 10;172h_ip->protocol = 0x11;173h_ip->saddr = 0x00000000;174h_ip->daddr = 0xffffffff;175176header_size += sizeof(struct udphdr);177h_udp = (struct udphdr *)(h_ip + 1);178h_udp->source = GELIC_DEBUG_PORT;179h_udp->dest = GELIC_DEBUG_PORT;180181pmsgc = pmsg = (char *)(h_udp + 1);182}183184static void gelic_debug_shutdown(void)185{186if (bus_addr)187unmap_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID,188bus_addr, sizeof(dbg));189lv1_close_device(GELIC_BUS_ID, GELIC_DEVICE_ID);190}191192static void gelic_sendbuf(int msgsize)193{194u16 *p;195u32 sum;196int i;197198dbg.descr.buf_size = header_size + msgsize;199h_ip->tot_len = msgsize + sizeof(struct udphdr) +200sizeof(struct iphdr);201h_udp->len = msgsize + sizeof(struct udphdr);202203h_ip->check = 0;204sum = 0;205p = (u16 *)h_ip;206for (i = 0; i < 5; i++)207sum += *p++;208h_ip->check = ~(sum + (sum >> 16));209210dbg.descr.dmac_cmd_status = GELIC_DESCR_DMA_CMD_NO_CHKSUM |211GELIC_DESCR_TX_DMA_FRAME_TAIL;212dbg.descr.result_size = 0;213dbg.descr.data_status = 0;214215wmb();216217lv1_net_start_tx_dma(GELIC_BUS_ID, GELIC_DEVICE_ID, bus_addr, 0);218219while ((dbg.descr.dmac_cmd_status & GELIC_DESCR_DMA_STAT_MASK) ==220GELIC_DESCR_DMA_CARDOWNED)221cpu_relax();222}223224static void ps3gelic_udbg_putc(char ch)225{226*pmsgc++ = ch;227if (ch == '\n' || (pmsgc-pmsg) >= GELIC_MAX_MESSAGE_SIZE) {228gelic_sendbuf(pmsgc-pmsg);229pmsgc = pmsg;230}231}232233void __init udbg_init_ps3gelic(void)234{235gelic_debug_init();236udbg_putc = ps3gelic_udbg_putc;237}238239void udbg_shutdown_ps3gelic(void)240{241udbg_putc = NULL;242gelic_debug_shutdown();243}244EXPORT_SYMBOL(udbg_shutdown_ps3gelic);245246247