Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

misc: bcm-vk: add get_card_info, peerlog_info, and proc_mon_info

Add support to get card_info (details about card),
peerlog_info (to get details of peerlog on card),
and proc_mon_info (process monitoring on card).

This info is used for collection of logs via direct
read of BAR space and by sysfs access (in a follow on commit).

Co-developed-by: Desmond Yan <desmond.yan@broadcom.com>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Desmond Yan <desmond.yan@broadcom.com>
Signed-off-by: Scott Branden <scott.branden@broadcom.com>
Link: https://lore.kernel.org/r/20210120175827.14820-9-scott.branden@broadcom.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Scott Branden and committed by
Greg Kroah-Hartman
ff428d05 7367e0ad

+165
+60
drivers/misc/bcm-vk/bcm_vk.h
··· 205 205 206 206 #define BCM_VK_NUM_TTY 2 207 207 208 + /* VK device max power state, supports 3, full, reduced and low */ 209 + #define MAX_OPP 3 210 + #define MAX_CARD_INFO_TAG_SIZE 64 211 + 212 + struct bcm_vk_card_info { 213 + u32 version; 214 + char os_tag[MAX_CARD_INFO_TAG_SIZE]; 215 + char cmpt_tag[MAX_CARD_INFO_TAG_SIZE]; 216 + u32 cpu_freq_mhz; 217 + u32 cpu_scale[MAX_OPP]; 218 + u32 ddr_freq_mhz; 219 + u32 ddr_size_MB; 220 + u32 video_core_freq_mhz; 221 + }; 222 + 208 223 /* DAUTH related info */ 209 224 struct bcm_vk_dauth_key { 210 225 char store[VK_BAR1_DAUTH_STORE_SIZE]; ··· 230 215 struct bcm_vk_dauth_key keys[VK_BAR1_DAUTH_MAX]; 231 216 }; 232 217 218 + /* 219 + * Control structure of logging messages from the card. This 220 + * buffer is for logmsg that comes from vk 221 + */ 222 + struct bcm_vk_peer_log { 223 + u32 rd_idx; 224 + u32 wr_idx; 225 + u32 buf_size; 226 + u32 mask; 227 + char data[0]; 228 + }; 229 + 230 + /* max buf size allowed */ 231 + #define BCM_VK_PEER_LOG_BUF_MAX SZ_16K 232 + /* max size per line of peer log */ 233 + #define BCM_VK_PEER_LOG_LINE_MAX 256 234 + 235 + /* 236 + * single entry for processing type + utilization 237 + */ 238 + #define BCM_VK_PROC_TYPE_TAG_LEN 8 239 + struct bcm_vk_proc_mon_entry_t { 240 + char tag[BCM_VK_PROC_TYPE_TAG_LEN]; 241 + u32 used; 242 + u32 max; /**< max capacity */ 243 + }; 244 + 245 + /** 246 + * Structure for run time utilization 247 + */ 248 + #define BCM_VK_PROC_MON_MAX 8 /* max entries supported */ 249 + struct bcm_vk_proc_mon_info { 250 + u32 num; /**< no of entries */ 251 + u32 entry_size; /**< per entry size */ 252 + struct bcm_vk_proc_mon_entry_t entries[BCM_VK_PROC_MON_MAX]; 253 + }; 254 + 233 255 struct bcm_vk { 234 256 struct pci_dev *pdev; 235 257 void __iomem *bar[MAX_BAR]; 236 258 259 + struct bcm_vk_card_info card_info; 260 + struct bcm_vk_proc_mon_info proc_mon_info; 237 261 struct bcm_vk_dauth_info dauth_info; 238 262 239 263 /* mutex to protect the ioctls */ ··· 294 240 dma_addr_t tdma_addr; /* test dma segment bus addr */ 295 241 296 242 struct notifier_block panic_nb; 243 + 244 + /* offset of the peer log control in BAR2 */ 245 + u32 peerlog_off; 246 + struct bcm_vk_peer_log peerlog_info; /* record of peer log info */ 247 + /* offset of processing monitoring info in BAR2 */ 248 + u32 proc_mon_off; 297 249 }; 298 250 299 251 /* wq offload work items bits definitions */
+105
drivers/misc/bcm-vk/bcm_vk_dev.c
··· 172 172 return 0; 173 173 } 174 174 175 + static void bcm_vk_get_card_info(struct bcm_vk *vk) 176 + { 177 + struct device *dev = &vk->pdev->dev; 178 + u32 offset; 179 + int i; 180 + u8 *dst; 181 + struct bcm_vk_card_info *info = &vk->card_info; 182 + 183 + /* first read the offset from spare register */ 184 + offset = vkread32(vk, BAR_0, BAR_CARD_STATIC_INFO); 185 + offset &= (pci_resource_len(vk->pdev, BAR_2 * 2) - 1); 186 + 187 + /* based on the offset, read info to internal card info structure */ 188 + dst = (u8 *)info; 189 + for (i = 0; i < sizeof(*info); i++) 190 + *dst++ = vkread8(vk, BAR_2, offset++); 191 + 192 + #define CARD_INFO_LOG_FMT "version : %x\n" \ 193 + "os_tag : %s\n" \ 194 + "cmpt_tag : %s\n" \ 195 + "cpu_freq : %d MHz\n" \ 196 + "cpu_scale : %d full, %d lowest\n" \ 197 + "ddr_freq : %d MHz\n" \ 198 + "ddr_size : %d MB\n" \ 199 + "video_freq: %d MHz\n" 200 + dev_dbg(dev, CARD_INFO_LOG_FMT, info->version, info->os_tag, 201 + info->cmpt_tag, info->cpu_freq_mhz, info->cpu_scale[0], 202 + info->cpu_scale[MAX_OPP - 1], info->ddr_freq_mhz, 203 + info->ddr_size_MB, info->video_core_freq_mhz); 204 + 205 + /* 206 + * get the peer log pointer, only need the offset, and get record 207 + * of the log buffer information which would be used for checking 208 + * before dump, in case the BAR2 memory has been corrupted. 209 + */ 210 + vk->peerlog_off = offset; 211 + memcpy_fromio(&vk->peerlog_info, vk->bar[BAR_2] + vk->peerlog_off, 212 + sizeof(vk->peerlog_info)); 213 + 214 + /* 215 + * Do a range checking and if out of bound, the record will be zeroed 216 + * which guarantees that nothing would be dumped. In other words, 217 + * peer dump is disabled. 218 + */ 219 + if ((vk->peerlog_info.buf_size > BCM_VK_PEER_LOG_BUF_MAX) || 220 + (vk->peerlog_info.mask != (vk->peerlog_info.buf_size - 1)) || 221 + (vk->peerlog_info.rd_idx > vk->peerlog_info.mask) || 222 + (vk->peerlog_info.wr_idx > vk->peerlog_info.mask)) { 223 + dev_err(dev, "Peer log disabled - range error: Size 0x%x(0x%x), [Rd Wr] = [%d %d]\n", 224 + vk->peerlog_info.buf_size, 225 + vk->peerlog_info.mask, 226 + vk->peerlog_info.rd_idx, 227 + vk->peerlog_info.wr_idx); 228 + memset(&vk->peerlog_info, 0, sizeof(vk->peerlog_info)); 229 + } else { 230 + dev_dbg(dev, "Peer log: Size 0x%x(0x%x), [Rd Wr] = [%d %d]\n", 231 + vk->peerlog_info.buf_size, 232 + vk->peerlog_info.mask, 233 + vk->peerlog_info.rd_idx, 234 + vk->peerlog_info.wr_idx); 235 + } 236 + } 237 + 238 + static void bcm_vk_get_proc_mon_info(struct bcm_vk *vk) 239 + { 240 + struct device *dev = &vk->pdev->dev; 241 + struct bcm_vk_proc_mon_info *mon = &vk->proc_mon_info; 242 + u32 num, entry_size, offset, buf_size; 243 + u8 *dst; 244 + 245 + /* calculate offset which is based on peerlog offset */ 246 + buf_size = vkread32(vk, BAR_2, 247 + vk->peerlog_off 248 + + offsetof(struct bcm_vk_peer_log, buf_size)); 249 + offset = vk->peerlog_off + sizeof(struct bcm_vk_peer_log) 250 + + buf_size; 251 + 252 + /* first read the num and entry size */ 253 + num = vkread32(vk, BAR_2, offset); 254 + entry_size = vkread32(vk, BAR_2, offset + sizeof(num)); 255 + 256 + /* check for max allowed */ 257 + if (num > BCM_VK_PROC_MON_MAX) { 258 + dev_err(dev, "Processing monitoring entry %d exceeds max %d\n", 259 + num, BCM_VK_PROC_MON_MAX); 260 + return; 261 + } 262 + mon->num = num; 263 + mon->entry_size = entry_size; 264 + 265 + vk->proc_mon_off = offset; 266 + 267 + /* read it once that will capture those static info */ 268 + dst = (u8 *)&mon->entries[0]; 269 + offset += sizeof(num) + sizeof(entry_size); 270 + memcpy_fromio(dst, vk->bar[BAR_2] + offset, num * entry_size); 271 + } 272 + 175 273 static int bcm_vk_sync_card_info(struct bcm_vk *vk) 176 274 { 177 275 u32 rdy_marker = vkread32(vk, BAR_1, VK_BAR1_MSGQ_DEF_RDY); ··· 291 193 vkwrite32(vk, nr_scratch_pages * PAGE_SIZE, BAR_1, 292 194 VK_BAR1_SCRATCH_SZ_ADDR); 293 195 } 196 + 197 + /* get static card info, only need to read once */ 198 + bcm_vk_get_card_info(vk); 199 + 200 + /* get the proc mon info once */ 201 + bcm_vk_get_proc_mon_info(vk); 202 + 294 203 return 0; 295 204 } 296 205