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

misc: bcm-vk: add VK messaging support

Add message support in order to be able to communicate
to VK card via message queues.

This info is used for debug purposes via 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-10-scott.branden@broadcom.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Scott Branden and committed by
Greg Kroah-Hartman
111d746b ff428d05

+2087 -3
+2 -1
drivers/misc/bcm-vk/Makefile
··· 6 6 obj-$(CONFIG_BCM_VK) += bcm_vk.o 7 7 bcm_vk-objs := \ 8 8 bcm_vk_dev.o \ 9 - bcm_vk_msg.o 9 + bcm_vk_msg.o \ 10 + bcm_vk_sg.o 10 11
+123
drivers/misc/bcm-vk/bcm_vk.h
··· 6 6 #ifndef BCM_VK_H 7 7 #define BCM_VK_H 8 8 9 + #include <linux/atomic.h> 9 10 #include <linux/firmware.h> 10 11 #include <linux/kref.h> 11 12 #include <linux/miscdevice.h> 12 13 #include <linux/mutex.h> 13 14 #include <linux/pci.h> 15 + #include <linux/poll.h> 14 16 #include <linux/sched/signal.h> 15 17 #include <linux/uaccess.h> 16 18 #include <uapi/linux/misc/bcm_vk.h> ··· 95 93 #define MAJOR_SOC_REV(_chip_id) (((_chip_id) >> 20) & 0xf) 96 94 97 95 #define BAR_CARD_TEMPERATURE 0x45c 96 + /* defines for all temperature sensor */ 97 + #define BCM_VK_TEMP_FIELD_MASK 0xff 98 + #define BCM_VK_CPU_TEMP_SHIFT 0 99 + #define BCM_VK_DDR0_TEMP_SHIFT 8 100 + #define BCM_VK_DDR1_TEMP_SHIFT 16 98 101 99 102 #define BAR_CARD_VOLTAGE 0x460 103 + /* defines for voltage rail conversion */ 104 + #define BCM_VK_VOLT_RAIL_MASK 0xffff 105 + #define BCM_VK_3P3_VOLT_REG_SHIFT 16 100 106 101 107 #define BAR_CARD_ERR_LOG 0x464 108 + /* Error log register bit definition - register for error alerts */ 109 + #define ERR_LOG_UECC BIT(0) 110 + #define ERR_LOG_SSIM_BUSY BIT(1) 111 + #define ERR_LOG_AFBC_BUSY BIT(2) 112 + #define ERR_LOG_HIGH_TEMP_ERR BIT(3) 113 + #define ERR_LOG_WDOG_TIMEOUT BIT(4) 114 + #define ERR_LOG_SYS_FAULT BIT(5) 115 + #define ERR_LOG_RAMDUMP BIT(6) 116 + #define ERR_LOG_COP_WDOG_TIMEOUT BIT(7) 117 + /* warnings */ 118 + #define ERR_LOG_MEM_ALLOC_FAIL BIT(8) 119 + #define ERR_LOG_LOW_TEMP_WARN BIT(9) 120 + #define ERR_LOG_ECC BIT(10) 121 + #define ERR_LOG_IPC_DWN BIT(11) 122 + 123 + /* Alert bit definitions detectd on host */ 124 + #define ERR_LOG_HOST_INTF_V_FAIL BIT(13) 125 + #define ERR_LOG_HOST_HB_FAIL BIT(14) 126 + #define ERR_LOG_HOST_PCIE_DWN BIT(15) 102 127 103 128 #define BAR_CARD_ERR_MEM 0x468 129 + /* defines for mem err, all fields have same width */ 130 + #define BCM_VK_MEM_ERR_FIELD_MASK 0xff 131 + #define BCM_VK_ECC_MEM_ERR_SHIFT 0 132 + #define BCM_VK_UECC_MEM_ERR_SHIFT 8 133 + /* threshold of event occurrence and logs start to come out */ 134 + #define BCM_VK_ECC_THRESHOLD 10 135 + #define BCM_VK_UECC_THRESHOLD 1 104 136 105 137 #define BAR_CARD_PWR_AND_THRE 0x46c 138 + /* defines for power and temp threshold, all fields have same width */ 139 + #define BCM_VK_PWR_AND_THRE_FIELD_MASK 0xff 140 + #define BCM_VK_LOW_TEMP_THRE_SHIFT 0 141 + #define BCM_VK_HIGH_TEMP_THRE_SHIFT 8 142 + #define BCM_VK_PWR_STATE_SHIFT 16 106 143 107 144 #define BAR_CARD_STATIC_INFO 0x470 108 145 ··· 183 142 /* Card OS Firmware version size */ 184 143 #define BAR_FIRMWARE_TAG_SIZE 50 185 144 #define FIRMWARE_STATUS_PRE_INIT_DONE 0x1f 145 + 146 + /* VK MSG_ID defines */ 147 + #define VK_MSG_ID_BITMAP_SIZE 4096 148 + #define VK_MSG_ID_BITMAP_MASK (VK_MSG_ID_BITMAP_SIZE - 1) 149 + #define VK_MSG_ID_OVERFLOW 0xffff 186 150 187 151 /* 188 152 * BAR1 ··· 242 196 243 197 /* VK device supports a maximum of 3 bars */ 244 198 #define MAX_BAR 3 199 + 200 + /* default number of msg blk for inband SGL */ 201 + #define BCM_VK_DEF_IB_SGL_BLK_LEN 16 202 + #define BCM_VK_IB_SGL_BLK_MAX 24 245 203 246 204 enum pci_barno { 247 205 BAR_0 = 0, ··· 317 267 struct bcm_vk_proc_mon_entry_t entries[BCM_VK_PROC_MON_MAX]; 318 268 }; 319 269 270 + struct bcm_vk_hb_ctrl { 271 + struct timer_list timer; 272 + u32 last_uptime; 273 + u32 lost_cnt; 274 + }; 275 + 276 + struct bcm_vk_alert { 277 + u16 flags; 278 + u16 notfs; 279 + }; 280 + 281 + /* some alert counters that the driver will keep track */ 282 + struct bcm_vk_alert_cnts { 283 + u16 ecc; 284 + u16 uecc; 285 + }; 286 + 320 287 struct bcm_vk { 321 288 struct pci_dev *pdev; 322 289 void __iomem *bar[MAX_BAR]; 290 + int num_irqs; 323 291 324 292 struct bcm_vk_card_info card_info; 325 293 struct bcm_vk_proc_mon_info proc_mon_info; ··· 351 283 /* Reference-counting to handle file operations */ 352 284 struct kref kref; 353 285 286 + spinlock_t msg_id_lock; /* Spinlock for msg_id */ 287 + u16 msg_id; 288 + DECLARE_BITMAP(bmap, VK_MSG_ID_BITMAP_SIZE); 354 289 spinlock_t ctx_lock; /* Spinlock for component context */ 355 290 struct bcm_vk_ctx ctx[VK_CMPT_CTX_MAX]; 356 291 struct bcm_vk_ht_entry pid_ht[VK_PID_HT_SZ]; 292 + pid_t reset_pid; /* process that issue reset */ 293 + 294 + atomic_t msgq_inited; /* indicate if info has been synced with vk */ 295 + struct bcm_vk_msg_chan to_v_msg_chan; 296 + struct bcm_vk_msg_chan to_h_msg_chan; 357 297 358 298 struct workqueue_struct *wq_thread; 359 299 struct work_struct wq_work; /* work queue for deferred job */ ··· 370 294 dma_addr_t tdma_addr; /* test dma segment bus addr */ 371 295 372 296 struct notifier_block panic_nb; 297 + u32 ib_sgl_size; /* size allocated for inband sgl insertion */ 298 + 299 + /* heart beat mechanism control structure */ 300 + struct bcm_vk_hb_ctrl hb_ctrl; 301 + /* house-keeping variable of error logs */ 302 + spinlock_t host_alert_lock; /* protection to access host_alert struct */ 303 + struct bcm_vk_alert host_alert; 304 + struct bcm_vk_alert peer_alert; /* bits set by the card */ 305 + struct bcm_vk_alert_cnts alert_cnts; 373 306 374 307 /* offset of the peer log control in BAR2 */ 375 308 u32 peerlog_off; ··· 391 306 enum bcm_vk_wq_offload_flags { 392 307 BCM_VK_WQ_DWNLD_PEND = 0, 393 308 BCM_VK_WQ_DWNLD_AUTO = 1, 309 + BCM_VK_WQ_NOTF_PEND = 2, 394 310 }; 311 + 312 + /* a macro to get an individual field with mask and shift */ 313 + #define BCM_VK_EXTRACT_FIELD(_field, _reg, _mask, _shift) \ 314 + (_field = (((_reg) >> (_shift)) & (_mask))) 315 + 316 + struct bcm_vk_entry { 317 + const u32 mask; 318 + const u32 exp_val; 319 + const char *str; 320 + }; 321 + 322 + /* alerts that could be generated from peer */ 323 + #define BCM_VK_PEER_ERR_NUM 12 324 + extern struct bcm_vk_entry const bcm_vk_peer_err[BCM_VK_PEER_ERR_NUM]; 325 + /* alerts detected by the host */ 326 + #define BCM_VK_HOST_ERR_NUM 3 327 + extern struct bcm_vk_entry const bcm_vk_host_err[BCM_VK_HOST_ERR_NUM]; 395 328 396 329 /* 397 330 * check if PCIe interface is down on read. Use it when it is ··· 457 354 } 458 355 459 356 int bcm_vk_open(struct inode *inode, struct file *p_file); 357 + ssize_t bcm_vk_read(struct file *p_file, char __user *buf, size_t count, 358 + loff_t *f_pos); 359 + ssize_t bcm_vk_write(struct file *p_file, const char __user *buf, 360 + size_t count, loff_t *f_pos); 361 + __poll_t bcm_vk_poll(struct file *p_file, struct poll_table_struct *wait); 460 362 int bcm_vk_release(struct inode *inode, struct file *p_file); 461 363 void bcm_vk_release_data(struct kref *kref); 364 + irqreturn_t bcm_vk_msgq_irqhandler(int irq, void *dev_id); 365 + irqreturn_t bcm_vk_notf_irqhandler(int irq, void *dev_id); 366 + int bcm_vk_msg_init(struct bcm_vk *vk); 367 + void bcm_vk_msg_remove(struct bcm_vk *vk); 368 + int bcm_vk_sync_msgq(struct bcm_vk *vk, bool force_sync); 369 + void bcm_vk_blk_drv_access(struct bcm_vk *vk); 370 + s32 bcm_to_h_msg_dequeue(struct bcm_vk *vk); 371 + int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type, 372 + const pid_t pid, const u32 q_num); 373 + void bcm_to_v_q_doorbell(struct bcm_vk *vk, u32 q_num, u32 db_val); 462 374 int bcm_vk_auto_load_all_images(struct bcm_vk *vk); 375 + void bcm_vk_hb_init(struct bcm_vk *vk); 376 + void bcm_vk_hb_deinit(struct bcm_vk *vk); 377 + void bcm_vk_handle_notf(struct bcm_vk *vk); 378 + bool bcm_vk_drv_access_ok(struct bcm_vk *vk); 379 + void bcm_vk_set_host_alert(struct bcm_vk *vk, u32 bit_mask); 463 380 464 381 #endif
+307 -2
drivers/misc/bcm-vk/bcm_vk_dev.c
··· 8 8 #include <linux/firmware.h> 9 9 #include <linux/fs.h> 10 10 #include <linux/idr.h> 11 + #include <linux/interrupt.h> 11 12 #include <linux/kref.h> 12 13 #include <linux/module.h> 13 14 #include <linux/mutex.h> ··· 103 102 module_param(nr_scratch_pages, uint, 0444); 104 103 MODULE_PARM_DESC(nr_scratch_pages, 105 104 "Number of pre allocated DMAable coherent pages.\n"); 105 + static uint nr_ib_sgl_blk = BCM_VK_DEF_IB_SGL_BLK_LEN; 106 + module_param(nr_ib_sgl_blk, uint, 0444); 107 + MODULE_PARM_DESC(nr_ib_sgl_blk, 108 + "Number of in-band msg blks for short SGL.\n"); 109 + 110 + /* 111 + * alerts that could be generated from peer 112 + */ 113 + const struct bcm_vk_entry bcm_vk_peer_err[BCM_VK_PEER_ERR_NUM] = { 114 + {ERR_LOG_UECC, ERR_LOG_UECC, "uecc"}, 115 + {ERR_LOG_SSIM_BUSY, ERR_LOG_SSIM_BUSY, "ssim_busy"}, 116 + {ERR_LOG_AFBC_BUSY, ERR_LOG_AFBC_BUSY, "afbc_busy"}, 117 + {ERR_LOG_HIGH_TEMP_ERR, ERR_LOG_HIGH_TEMP_ERR, "high_temp"}, 118 + {ERR_LOG_WDOG_TIMEOUT, ERR_LOG_WDOG_TIMEOUT, "wdog_timeout"}, 119 + {ERR_LOG_SYS_FAULT, ERR_LOG_SYS_FAULT, "sys_fault"}, 120 + {ERR_LOG_RAMDUMP, ERR_LOG_RAMDUMP, "ramdump"}, 121 + {ERR_LOG_COP_WDOG_TIMEOUT, ERR_LOG_COP_WDOG_TIMEOUT, 122 + "cop_wdog_timeout"}, 123 + {ERR_LOG_MEM_ALLOC_FAIL, ERR_LOG_MEM_ALLOC_FAIL, "malloc_fail warn"}, 124 + {ERR_LOG_LOW_TEMP_WARN, ERR_LOG_LOW_TEMP_WARN, "low_temp warn"}, 125 + {ERR_LOG_ECC, ERR_LOG_ECC, "ecc"}, 126 + {ERR_LOG_IPC_DWN, ERR_LOG_IPC_DWN, "ipc_down"}, 127 + }; 128 + 129 + /* alerts detected by the host */ 130 + const struct bcm_vk_entry bcm_vk_host_err[BCM_VK_HOST_ERR_NUM] = { 131 + {ERR_LOG_HOST_PCIE_DWN, ERR_LOG_HOST_PCIE_DWN, "PCIe_down"}, 132 + {ERR_LOG_HOST_HB_FAIL, ERR_LOG_HOST_HB_FAIL, "hb_fail"}, 133 + {ERR_LOG_HOST_INTF_V_FAIL, ERR_LOG_HOST_INTF_V_FAIL, "intf_ver_fail"}, 134 + }; 135 + 136 + irqreturn_t bcm_vk_notf_irqhandler(int irq, void *dev_id) 137 + { 138 + struct bcm_vk *vk = dev_id; 139 + 140 + if (!bcm_vk_drv_access_ok(vk)) { 141 + dev_err(&vk->pdev->dev, 142 + "Interrupt %d received when msgq not inited\n", irq); 143 + goto skip_schedule_work; 144 + } 145 + 146 + /* if notification is not pending, set bit and schedule work */ 147 + if (test_and_set_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload) == 0) 148 + queue_work(vk->wq_thread, &vk->wq_work); 149 + 150 + skip_schedule_work: 151 + return IRQ_HANDLED; 152 + } 106 153 107 154 static int bcm_vk_intf_ver_chk(struct bcm_vk *vk) 108 155 { ··· 175 126 dev_err(dev, 176 127 "Intf major.minor=%d.%d rejected - drv %d.%d\n", 177 128 major, minor, SEMANTIC_MAJOR, SEMANTIC_MINOR); 129 + bcm_vk_set_host_alert(vk, ERR_LOG_HOST_INTF_V_FAIL); 178 130 ret = -EPFNOSUPPORT; 179 131 } else { 180 132 dev_dbg(dev, ··· 183 133 major, minor, SEMANTIC_MAJOR, SEMANTIC_MINOR); 184 134 } 185 135 return ret; 136 + } 137 + 138 + static void bcm_vk_log_notf(struct bcm_vk *vk, 139 + struct bcm_vk_alert *alert, 140 + struct bcm_vk_entry const *entry_tab, 141 + const u32 table_size) 142 + { 143 + u32 i; 144 + u32 masked_val, latched_val; 145 + struct bcm_vk_entry const *entry; 146 + u32 reg; 147 + u16 ecc_mem_err, uecc_mem_err; 148 + struct device *dev = &vk->pdev->dev; 149 + 150 + for (i = 0; i < table_size; i++) { 151 + entry = &entry_tab[i]; 152 + masked_val = entry->mask & alert->notfs; 153 + latched_val = entry->mask & alert->flags; 154 + 155 + if (masked_val == ERR_LOG_UECC) { 156 + /* 157 + * if there is difference between stored cnt and it 158 + * is greater than threshold, log it. 159 + */ 160 + reg = vkread32(vk, BAR_0, BAR_CARD_ERR_MEM); 161 + BCM_VK_EXTRACT_FIELD(uecc_mem_err, reg, 162 + BCM_VK_MEM_ERR_FIELD_MASK, 163 + BCM_VK_UECC_MEM_ERR_SHIFT); 164 + if ((uecc_mem_err != vk->alert_cnts.uecc) && 165 + (uecc_mem_err >= BCM_VK_UECC_THRESHOLD)) 166 + dev_info(dev, 167 + "ALERT! %s.%d uecc RAISED - ErrCnt %d\n", 168 + DRV_MODULE_NAME, vk->devid, 169 + uecc_mem_err); 170 + vk->alert_cnts.uecc = uecc_mem_err; 171 + } else if (masked_val == ERR_LOG_ECC) { 172 + reg = vkread32(vk, BAR_0, BAR_CARD_ERR_MEM); 173 + BCM_VK_EXTRACT_FIELD(ecc_mem_err, reg, 174 + BCM_VK_MEM_ERR_FIELD_MASK, 175 + BCM_VK_ECC_MEM_ERR_SHIFT); 176 + if ((ecc_mem_err != vk->alert_cnts.ecc) && 177 + (ecc_mem_err >= BCM_VK_ECC_THRESHOLD)) 178 + dev_info(dev, "ALERT! %s.%d ecc RAISED - ErrCnt %d\n", 179 + DRV_MODULE_NAME, vk->devid, 180 + ecc_mem_err); 181 + vk->alert_cnts.ecc = ecc_mem_err; 182 + } else if (masked_val != latched_val) { 183 + /* print a log as info */ 184 + dev_info(dev, "ALERT! %s.%d %s %s\n", 185 + DRV_MODULE_NAME, vk->devid, entry->str, 186 + masked_val ? "RAISED" : "CLEARED"); 187 + } 188 + } 189 + } 190 + 191 + static void bcm_vk_dump_peer_log(struct bcm_vk *vk) 192 + { 193 + struct bcm_vk_peer_log log; 194 + struct bcm_vk_peer_log *log_info = &vk->peerlog_info; 195 + char loc_buf[BCM_VK_PEER_LOG_LINE_MAX]; 196 + int cnt; 197 + struct device *dev = &vk->pdev->dev; 198 + unsigned int data_offset; 199 + 200 + memcpy_fromio(&log, vk->bar[BAR_2] + vk->peerlog_off, sizeof(log)); 201 + 202 + dev_dbg(dev, "Peer PANIC: Size 0x%x(0x%x), [Rd Wr] = [%d %d]\n", 203 + log.buf_size, log.mask, log.rd_idx, log.wr_idx); 204 + 205 + if (!log_info->buf_size) { 206 + dev_err(dev, "Peer log dump disabled - skipped!\n"); 207 + return; 208 + } 209 + 210 + /* perform range checking for rd/wr idx */ 211 + if ((log.rd_idx > log_info->mask) || 212 + (log.wr_idx > log_info->mask) || 213 + (log.buf_size != log_info->buf_size) || 214 + (log.mask != log_info->mask)) { 215 + dev_err(dev, 216 + "Corrupted Ptrs: Size 0x%x(0x%x) Mask 0x%x(0x%x) [Rd Wr] = [%d %d], skip log dump.\n", 217 + log_info->buf_size, log.buf_size, 218 + log_info->mask, log.mask, 219 + log.rd_idx, log.wr_idx); 220 + return; 221 + } 222 + 223 + cnt = 0; 224 + data_offset = vk->peerlog_off + sizeof(struct bcm_vk_peer_log); 225 + loc_buf[BCM_VK_PEER_LOG_LINE_MAX - 1] = '\0'; 226 + while (log.rd_idx != log.wr_idx) { 227 + loc_buf[cnt] = vkread8(vk, BAR_2, data_offset + log.rd_idx); 228 + 229 + if ((loc_buf[cnt] == '\0') || 230 + (cnt == (BCM_VK_PEER_LOG_LINE_MAX - 1))) { 231 + dev_err(dev, "%s", loc_buf); 232 + cnt = 0; 233 + } else { 234 + cnt++; 235 + } 236 + log.rd_idx = (log.rd_idx + 1) & log.mask; 237 + } 238 + /* update rd idx at the end */ 239 + vkwrite32(vk, log.rd_idx, BAR_2, 240 + vk->peerlog_off + offsetof(struct bcm_vk_peer_log, rd_idx)); 241 + } 242 + 243 + void bcm_vk_handle_notf(struct bcm_vk *vk) 244 + { 245 + u32 reg; 246 + struct bcm_vk_alert alert; 247 + bool intf_down; 248 + unsigned long flags; 249 + 250 + /* handle peer alerts and then locally detected ones */ 251 + reg = vkread32(vk, BAR_0, BAR_CARD_ERR_LOG); 252 + intf_down = BCM_VK_INTF_IS_DOWN(reg); 253 + if (!intf_down) { 254 + vk->peer_alert.notfs = reg; 255 + bcm_vk_log_notf(vk, &vk->peer_alert, bcm_vk_peer_err, 256 + ARRAY_SIZE(bcm_vk_peer_err)); 257 + vk->peer_alert.flags = vk->peer_alert.notfs; 258 + } else { 259 + /* turn off access */ 260 + bcm_vk_blk_drv_access(vk); 261 + } 262 + 263 + /* check and make copy of alert with lock and then free lock */ 264 + spin_lock_irqsave(&vk->host_alert_lock, flags); 265 + if (intf_down) 266 + vk->host_alert.notfs |= ERR_LOG_HOST_PCIE_DWN; 267 + 268 + alert = vk->host_alert; 269 + vk->host_alert.flags = vk->host_alert.notfs; 270 + spin_unlock_irqrestore(&vk->host_alert_lock, flags); 271 + 272 + /* call display with copy */ 273 + bcm_vk_log_notf(vk, &alert, bcm_vk_host_err, 274 + ARRAY_SIZE(bcm_vk_host_err)); 275 + 276 + /* 277 + * If it is a sys fault or heartbeat timeout, we would like extract 278 + * log msg from the card so that we would know what is the last fault 279 + */ 280 + if (!intf_down && 281 + ((vk->host_alert.flags & ERR_LOG_HOST_HB_FAIL) || 282 + (vk->peer_alert.flags & ERR_LOG_SYS_FAULT))) 283 + bcm_vk_dump_peer_log(vk); 186 284 } 187 285 188 286 static inline int bcm_vk_wait(struct bcm_vk *vk, enum pci_barno bar, ··· 497 299 bcm_vk_get_proc_mon_info(vk); 498 300 499 301 return 0; 302 + } 303 + 304 + void bcm_vk_blk_drv_access(struct bcm_vk *vk) 305 + { 306 + int i; 307 + 308 + /* 309 + * kill all the apps 310 + */ 311 + spin_lock(&vk->ctx_lock); 312 + 313 + /* set msgq_inited to 0 so that all rd/wr will be blocked */ 314 + atomic_set(&vk->msgq_inited, 0); 315 + 316 + for (i = 0; i < VK_PID_HT_SZ; i++) { 317 + struct bcm_vk_ctx *ctx; 318 + 319 + list_for_each_entry(ctx, &vk->pid_ht[i].head, node) { 320 + dev_dbg(&vk->pdev->dev, 321 + "Send kill signal to pid %d\n", 322 + ctx->pid); 323 + kill_pid(find_vpid(ctx->pid), SIGKILL, 1); 324 + } 325 + } 326 + spin_unlock(&vk->ctx_lock); 500 327 } 501 328 502 329 static void bcm_vk_buf_notify(struct bcm_vk *vk, void *bufp, ··· 741 518 goto err_firmware_out; 742 519 } 743 520 521 + /* 522 + * Next, initialize Message Q if we are loading boot2. 523 + * Do a force sync 524 + */ 525 + ret = bcm_vk_sync_msgq(vk, true); 526 + if (ret) { 527 + dev_err(dev, "Boot2 Error reading comm msg Q info\n"); 528 + ret = -EIO; 529 + goto err_firmware_out; 530 + } 531 + 744 532 /* sync & channel other info */ 745 533 ret = bcm_vk_sync_card_info(vk); 746 534 if (ret) { ··· 902 668 } 903 669 904 670 /* 905 - * deferred work queue for auto download. 671 + * deferred work queue for draining and auto download. 906 672 */ 907 673 static void bcm_vk_wq_handler(struct work_struct *work) 908 674 { 909 675 struct bcm_vk *vk = container_of(work, struct bcm_vk, wq_work); 676 + struct device *dev = &vk->pdev->dev; 677 + s32 ret; 910 678 679 + /* check wq offload bit map to perform various operations */ 680 + if (test_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload)) { 681 + /* clear bit right the way for notification */ 682 + clear_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload); 683 + bcm_vk_handle_notf(vk); 684 + } 911 685 if (test_bit(BCM_VK_WQ_DWNLD_AUTO, vk->wq_offload)) { 912 686 bcm_vk_auto_load_all_images(vk); 913 687 ··· 926 684 clear_bit(BCM_VK_WQ_DWNLD_AUTO, vk->wq_offload); 927 685 clear_bit(BCM_VK_WQ_DWNLD_PEND, vk->wq_offload); 928 686 } 687 + 688 + /* next, try to drain */ 689 + ret = bcm_to_h_msg_dequeue(vk); 690 + 691 + if (ret == 0) 692 + dev_dbg(dev, "Spurious trigger for workqueue\n"); 693 + else if (ret < 0) 694 + bcm_vk_blk_drv_access(vk); 929 695 } 930 696 931 697 static long bcm_vk_load_image(struct bcm_vk *vk, ··· 1087 837 static const struct file_operations bcm_vk_fops = { 1088 838 .owner = THIS_MODULE, 1089 839 .open = bcm_vk_open, 840 + .read = bcm_vk_read, 841 + .write = bcm_vk_write, 842 + .poll = bcm_vk_poll, 1090 843 .release = bcm_vk_release, 1091 844 .unlocked_ioctl = bcm_vk_ioctl, 1092 845 }; ··· 1122 869 return -ENOMEM; 1123 870 1124 871 kref_init(&vk->kref); 872 + if (nr_ib_sgl_blk > BCM_VK_IB_SGL_BLK_MAX) { 873 + dev_warn(dev, "Inband SGL blk %d limited to max %d\n", 874 + nr_ib_sgl_blk, BCM_VK_IB_SGL_BLK_MAX); 875 + nr_ib_sgl_blk = BCM_VK_IB_SGL_BLK_MAX; 876 + } 877 + vk->ib_sgl_size = nr_ib_sgl_blk * VK_MSGQ_BLK_SIZE; 1125 878 mutex_init(&vk->mutex); 1126 879 1127 880 err = pci_enable_device(pdev); ··· 1191 932 } 1192 933 } 1193 934 935 + for (vk->num_irqs = 0; 936 + vk->num_irqs < VK_MSIX_MSGQ_MAX; 937 + vk->num_irqs++) { 938 + err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs), 939 + bcm_vk_msgq_irqhandler, 940 + IRQF_SHARED, DRV_MODULE_NAME, vk); 941 + if (err) { 942 + dev_err(dev, "failed to request msgq IRQ %d for MSIX %d\n", 943 + pdev->irq + vk->num_irqs, vk->num_irqs + 1); 944 + goto err_irq; 945 + } 946 + } 947 + /* one irq for notification from VK */ 948 + err = devm_request_irq(dev, pci_irq_vector(pdev, vk->num_irqs), 949 + bcm_vk_notf_irqhandler, 950 + IRQF_SHARED, DRV_MODULE_NAME, vk); 951 + if (err) { 952 + dev_err(dev, "failed to request notf IRQ %d for MSIX %d\n", 953 + pdev->irq + vk->num_irqs, vk->num_irqs + 1); 954 + goto err_irq; 955 + } 956 + vk->num_irqs++; 957 + 1194 958 id = ida_simple_get(&bcm_vk_ida, 0, 0, GFP_KERNEL); 1195 959 if (id < 0) { 1196 960 err = id; 1197 961 dev_err(dev, "unable to get id\n"); 1198 - goto err_iounmap; 962 + goto err_irq; 1199 963 } 1200 964 1201 965 vk->devid = id; ··· 1246 964 dev_err(dev, "Fail to create workqueue thread\n"); 1247 965 err = -ENOMEM; 1248 966 goto err_misc_deregister; 967 + } 968 + 969 + err = bcm_vk_msg_init(vk); 970 + if (err) { 971 + dev_err(dev, "failed to init msg queue info\n"); 972 + goto err_destroy_workqueue; 1249 973 } 1250 974 1251 975 /* sync other info */ ··· 1282 994 } 1283 995 } 1284 996 997 + /* enable hb */ 998 + bcm_vk_hb_init(vk); 999 + 1285 1000 dev_dbg(dev, "BCM-VK:%u created\n", id); 1286 1001 1287 1002 return 0; ··· 1305 1014 1306 1015 err_ida_remove: 1307 1016 ida_simple_remove(&bcm_vk_ida, id); 1017 + 1018 + err_irq: 1019 + for (i = 0; i < vk->num_irqs; i++) 1020 + devm_free_irq(dev, pci_irq_vector(pdev, i), vk); 1021 + 1022 + pci_disable_msix(pdev); 1023 + pci_disable_msi(pdev); 1308 1024 1309 1025 err_iounmap: 1310 1026 for (i = 0; i < MAX_BAR; i++) { ··· 1351 1053 struct bcm_vk *vk = pci_get_drvdata(pdev); 1352 1054 struct miscdevice *misc_device = &vk->miscdev; 1353 1055 1056 + bcm_vk_hb_deinit(vk); 1057 + 1354 1058 /* 1355 1059 * Trigger a reset to card and wait enough time for UCODE to rerun, 1356 1060 * which re-initialize the card into its default state. ··· 1376 1076 kfree(misc_device->name); 1377 1077 ida_simple_remove(&bcm_vk_ida, vk->devid); 1378 1078 } 1079 + for (i = 0; i < vk->num_irqs; i++) 1080 + devm_free_irq(&pdev->dev, pci_irq_vector(pdev, i), vk); 1081 + 1082 + pci_disable_msix(pdev); 1083 + pci_disable_msi(pdev); 1379 1084 1380 1085 cancel_work_sync(&vk->wq_work); 1381 1086 destroy_workqueue(vk->wq_thread);
+1187
drivers/misc/bcm-vk/bcm_vk_msg.c
··· 3 3 * Copyright 2018-2020 Broadcom. 4 4 */ 5 5 6 + #include <linux/delay.h> 7 + #include <linux/fs.h> 8 + #include <linux/hash.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/list.h> 11 + #include <linux/module.h> 12 + #include <linux/poll.h> 13 + #include <linux/sizes.h> 14 + #include <linux/spinlock.h> 15 + #include <linux/timer.h> 16 + 6 17 #include "bcm_vk.h" 7 18 #include "bcm_vk_msg.h" 19 + #include "bcm_vk_sg.h" 20 + 21 + /* functions to manipulate the transport id in msg block */ 22 + #define BCM_VK_MSG_Q_SHIFT 4 23 + #define BCM_VK_MSG_Q_MASK 0xF 24 + #define BCM_VK_MSG_ID_MASK 0xFFF 25 + 26 + #define BCM_VK_DMA_DRAIN_MAX_MS 2000 27 + 28 + /* number x q_size will be the max number of msg processed per loop */ 29 + #define BCM_VK_MSG_PROC_MAX_LOOP 2 30 + 31 + /* module parameter */ 32 + static bool hb_mon = true; 33 + module_param(hb_mon, bool, 0444); 34 + MODULE_PARM_DESC(hb_mon, "Monitoring heartbeat continuously.\n"); 35 + static int batch_log = 1; 36 + module_param(batch_log, int, 0444); 37 + MODULE_PARM_DESC(batch_log, "Max num of logs per batch operation.\n"); 38 + 39 + static bool hb_mon_is_on(void) 40 + { 41 + return hb_mon; 42 + } 43 + 44 + static u32 get_q_num(const struct vk_msg_blk *msg) 45 + { 46 + u32 q_num = msg->trans_id & BCM_VK_MSG_Q_MASK; 47 + 48 + if (q_num >= VK_MSGQ_PER_CHAN_MAX) 49 + q_num = VK_MSGQ_NUM_DEFAULT; 50 + return q_num; 51 + } 52 + 53 + static void set_q_num(struct vk_msg_blk *msg, u32 q_num) 54 + { 55 + msg->trans_id = (msg->trans_id & ~BCM_VK_MSG_Q_MASK) | 56 + (q_num >= VK_MSGQ_PER_CHAN_MAX) ? VK_MSGQ_NUM_DEFAULT : q_num; 57 + } 58 + 59 + static u32 get_msg_id(const struct vk_msg_blk *msg) 60 + { 61 + return ((msg->trans_id >> BCM_VK_MSG_Q_SHIFT) & BCM_VK_MSG_ID_MASK); 62 + } 63 + 64 + static void set_msg_id(struct vk_msg_blk *msg, u32 val) 65 + { 66 + msg->trans_id = (val << BCM_VK_MSG_Q_SHIFT) | get_q_num(msg); 67 + } 68 + 69 + static u32 msgq_inc(const struct bcm_vk_sync_qinfo *qinfo, u32 idx, u32 inc) 70 + { 71 + return ((idx + inc) & qinfo->q_mask); 72 + } 73 + 74 + static 75 + struct vk_msg_blk __iomem *msgq_blk_addr(const struct bcm_vk_sync_qinfo *qinfo, 76 + u32 idx) 77 + { 78 + return qinfo->q_start + (VK_MSGQ_BLK_SIZE * idx); 79 + } 80 + 81 + static u32 msgq_occupied(const struct bcm_vk_msgq __iomem *msgq, 82 + const struct bcm_vk_sync_qinfo *qinfo) 83 + { 84 + u32 wr_idx, rd_idx; 85 + 86 + wr_idx = readl_relaxed(&msgq->wr_idx); 87 + rd_idx = readl_relaxed(&msgq->rd_idx); 88 + 89 + return ((wr_idx - rd_idx) & qinfo->q_mask); 90 + } 91 + 92 + static 93 + u32 msgq_avail_space(const struct bcm_vk_msgq __iomem *msgq, 94 + const struct bcm_vk_sync_qinfo *qinfo) 95 + { 96 + return (qinfo->q_size - msgq_occupied(msgq, qinfo) - 1); 97 + } 98 + 99 + /* number of retries when enqueue message fails before returning EAGAIN */ 100 + #define BCM_VK_H2VK_ENQ_RETRY 10 101 + #define BCM_VK_H2VK_ENQ_RETRY_DELAY_MS 50 102 + 103 + bool bcm_vk_drv_access_ok(struct bcm_vk *vk) 104 + { 105 + return (!!atomic_read(&vk->msgq_inited)); 106 + } 107 + 108 + void bcm_vk_set_host_alert(struct bcm_vk *vk, u32 bit_mask) 109 + { 110 + struct bcm_vk_alert *alert = &vk->host_alert; 111 + unsigned long flags; 112 + 113 + /* use irqsave version as this maybe called inside timer interrupt */ 114 + spin_lock_irqsave(&vk->host_alert_lock, flags); 115 + alert->notfs |= bit_mask; 116 + spin_unlock_irqrestore(&vk->host_alert_lock, flags); 117 + 118 + if (test_and_set_bit(BCM_VK_WQ_NOTF_PEND, vk->wq_offload) == 0) 119 + queue_work(vk->wq_thread, &vk->wq_work); 120 + } 121 + 122 + /* 123 + * Heartbeat related defines 124 + * The heartbeat from host is a last resort. If stuck condition happens 125 + * on the card, firmware is supposed to detect it. Therefore, the heartbeat 126 + * values used will be more relaxed on the driver, which need to be bigger 127 + * than the watchdog timeout on the card. The watchdog timeout on the card 128 + * is 20s, with a jitter of 2s => 22s. We use a value of 27s here. 129 + */ 130 + #define BCM_VK_HB_TIMER_S 3 131 + #define BCM_VK_HB_TIMER_VALUE (BCM_VK_HB_TIMER_S * HZ) 132 + #define BCM_VK_HB_LOST_MAX (27 / BCM_VK_HB_TIMER_S) 133 + 134 + static void bcm_vk_hb_poll(struct timer_list *t) 135 + { 136 + u32 uptime_s; 137 + struct bcm_vk_hb_ctrl *hb = container_of(t, struct bcm_vk_hb_ctrl, 138 + timer); 139 + struct bcm_vk *vk = container_of(hb, struct bcm_vk, hb_ctrl); 140 + 141 + if (bcm_vk_drv_access_ok(vk) && hb_mon_is_on()) { 142 + /* read uptime from register and compare */ 143 + uptime_s = vkread32(vk, BAR_0, BAR_OS_UPTIME); 144 + 145 + if (uptime_s == hb->last_uptime) 146 + hb->lost_cnt++; 147 + else /* reset to avoid accumulation */ 148 + hb->lost_cnt = 0; 149 + 150 + dev_dbg(&vk->pdev->dev, "Last uptime %d current %d, lost %d\n", 151 + hb->last_uptime, uptime_s, hb->lost_cnt); 152 + 153 + /* 154 + * if the interface goes down without any activity, a value 155 + * of 0xFFFFFFFF will be continuously read, and the detection 156 + * will be happened eventually. 157 + */ 158 + hb->last_uptime = uptime_s; 159 + } else { 160 + /* reset heart beat lost cnt */ 161 + hb->lost_cnt = 0; 162 + } 163 + 164 + /* next, check if heartbeat exceeds limit */ 165 + if (hb->lost_cnt > BCM_VK_HB_LOST_MAX) { 166 + dev_err(&vk->pdev->dev, "Heartbeat Misses %d times, %d s!\n", 167 + BCM_VK_HB_LOST_MAX, 168 + BCM_VK_HB_LOST_MAX * BCM_VK_HB_TIMER_S); 169 + 170 + bcm_vk_blk_drv_access(vk); 171 + bcm_vk_set_host_alert(vk, ERR_LOG_HOST_HB_FAIL); 172 + } 173 + /* re-arm timer */ 174 + mod_timer(&hb->timer, jiffies + BCM_VK_HB_TIMER_VALUE); 175 + } 176 + 177 + void bcm_vk_hb_init(struct bcm_vk *vk) 178 + { 179 + struct bcm_vk_hb_ctrl *hb = &vk->hb_ctrl; 180 + 181 + timer_setup(&hb->timer, bcm_vk_hb_poll, 0); 182 + mod_timer(&hb->timer, jiffies + BCM_VK_HB_TIMER_VALUE); 183 + } 184 + 185 + void bcm_vk_hb_deinit(struct bcm_vk *vk) 186 + { 187 + struct bcm_vk_hb_ctrl *hb = &vk->hb_ctrl; 188 + 189 + del_timer(&hb->timer); 190 + } 191 + 192 + static void bcm_vk_msgid_bitmap_clear(struct bcm_vk *vk, 193 + unsigned int start, 194 + unsigned int nbits) 195 + { 196 + spin_lock(&vk->msg_id_lock); 197 + bitmap_clear(vk->bmap, start, nbits); 198 + spin_unlock(&vk->msg_id_lock); 199 + } 8 200 9 201 /* 10 202 * allocate a ctx per file struct ··· 231 39 /* increase kref */ 232 40 kref_get(&vk->kref); 233 41 42 + /* clear counter */ 43 + atomic_set(&ctx->pend_cnt, 0); 44 + atomic_set(&ctx->dma_cnt, 0); 45 + init_waitqueue_head(&ctx->rd_wq); 46 + 234 47 all_in_use_exit: 235 48 spin_unlock(&vk->ctx_lock); 236 49 237 50 return ctx; 51 + } 52 + 53 + static u16 bcm_vk_get_msg_id(struct bcm_vk *vk) 54 + { 55 + u16 rc = VK_MSG_ID_OVERFLOW; 56 + u16 test_bit_count = 0; 57 + 58 + spin_lock(&vk->msg_id_lock); 59 + while (test_bit_count < (VK_MSG_ID_BITMAP_SIZE - 1)) { 60 + /* 61 + * first time come in this loop, msg_id will be 0 62 + * and the first one tested will be 1. We skip 63 + * VK_SIMPLEX_MSG_ID (0) for one way host2vk 64 + * communication 65 + */ 66 + vk->msg_id++; 67 + if (vk->msg_id == VK_MSG_ID_BITMAP_SIZE) 68 + vk->msg_id = 1; 69 + 70 + if (test_bit(vk->msg_id, vk->bmap)) { 71 + test_bit_count++; 72 + continue; 73 + } 74 + rc = vk->msg_id; 75 + bitmap_set(vk->bmap, vk->msg_id, 1); 76 + break; 77 + } 78 + spin_unlock(&vk->msg_id_lock); 79 + 80 + return rc; 238 81 } 239 82 240 83 static int bcm_vk_free_ctx(struct bcm_vk *vk, struct bcm_vk_ctx *ctx) ··· 309 82 return count; 310 83 } 311 84 85 + static void bcm_vk_free_wkent(struct device *dev, struct bcm_vk_wkent *entry) 86 + { 87 + int proc_cnt; 88 + 89 + bcm_vk_sg_free(dev, entry->dma, VK_DMA_MAX_ADDRS, &proc_cnt); 90 + if (proc_cnt) 91 + atomic_dec(&entry->ctx->dma_cnt); 92 + 93 + kfree(entry->to_h_msg); 94 + kfree(entry); 95 + } 96 + 97 + static void bcm_vk_drain_all_pend(struct device *dev, 98 + struct bcm_vk_msg_chan *chan, 99 + struct bcm_vk_ctx *ctx) 100 + { 101 + u32 num; 102 + struct bcm_vk_wkent *entry, *tmp; 103 + struct bcm_vk *vk; 104 + struct list_head del_q; 105 + 106 + if (ctx) 107 + vk = container_of(ctx->miscdev, struct bcm_vk, miscdev); 108 + 109 + INIT_LIST_HEAD(&del_q); 110 + spin_lock(&chan->pendq_lock); 111 + for (num = 0; num < chan->q_nr; num++) { 112 + list_for_each_entry_safe(entry, tmp, &chan->pendq[num], node) { 113 + if ((!ctx) || (entry->ctx->idx == ctx->idx)) { 114 + list_del(&entry->node); 115 + list_add_tail(&entry->node, &del_q); 116 + } 117 + } 118 + } 119 + spin_unlock(&chan->pendq_lock); 120 + 121 + /* batch clean up */ 122 + num = 0; 123 + list_for_each_entry_safe(entry, tmp, &del_q, node) { 124 + list_del(&entry->node); 125 + num++; 126 + if (ctx) { 127 + struct vk_msg_blk *msg; 128 + int bit_set; 129 + bool responded; 130 + u32 msg_id; 131 + 132 + /* if it is specific ctx, log for any stuck */ 133 + msg = entry->to_v_msg; 134 + msg_id = get_msg_id(msg); 135 + bit_set = test_bit(msg_id, vk->bmap); 136 + responded = entry->to_h_msg ? true : false; 137 + if (num <= batch_log) 138 + dev_info(dev, 139 + "Drained: fid %u size %u msg 0x%x(seq-%x) ctx 0x%x[fd-%d] args:[0x%x 0x%x] resp %s, bmap %d\n", 140 + msg->function_id, msg->size, 141 + msg_id, entry->seq_num, 142 + msg->context_id, entry->ctx->idx, 143 + msg->cmd, msg->arg, 144 + responded ? "T" : "F", bit_set); 145 + if (responded) 146 + atomic_dec(&ctx->pend_cnt); 147 + else if (bit_set) 148 + bcm_vk_msgid_bitmap_clear(vk, msg_id, 1); 149 + } 150 + bcm_vk_free_wkent(dev, entry); 151 + } 152 + if (num && ctx) 153 + dev_info(dev, "Total drained items %d [fd-%d]\n", 154 + num, ctx->idx); 155 + } 156 + 157 + /* 158 + * Function to sync up the messages queue info that is provided by BAR1 159 + */ 160 + int bcm_vk_sync_msgq(struct bcm_vk *vk, bool force_sync) 161 + { 162 + struct bcm_vk_msgq __iomem *msgq; 163 + struct device *dev = &vk->pdev->dev; 164 + u32 msgq_off; 165 + u32 num_q; 166 + struct bcm_vk_msg_chan *chan_list[] = {&vk->to_v_msg_chan, 167 + &vk->to_h_msg_chan}; 168 + struct bcm_vk_msg_chan *chan; 169 + int i, j; 170 + int ret = 0; 171 + 172 + /* 173 + * If the driver is loaded at startup where vk OS is not up yet, 174 + * the msgq-info may not be available until a later time. In 175 + * this case, we skip and the sync function is supposed to be 176 + * called again. 177 + */ 178 + if (!bcm_vk_msgq_marker_valid(vk)) { 179 + dev_info(dev, "BAR1 msgq marker not initialized.\n"); 180 + return -EAGAIN; 181 + } 182 + 183 + msgq_off = vkread32(vk, BAR_1, VK_BAR1_MSGQ_CTRL_OFF); 184 + 185 + /* each side is always half the total */ 186 + num_q = vkread32(vk, BAR_1, VK_BAR1_MSGQ_NR) / 2; 187 + if (!num_q || (num_q > VK_MSGQ_PER_CHAN_MAX)) { 188 + dev_err(dev, 189 + "Advertised msgq %d error - max %d allowed\n", 190 + num_q, VK_MSGQ_PER_CHAN_MAX); 191 + return -EINVAL; 192 + } 193 + 194 + vk->to_v_msg_chan.q_nr = num_q; 195 + vk->to_h_msg_chan.q_nr = num_q; 196 + 197 + /* first msgq location */ 198 + msgq = vk->bar[BAR_1] + msgq_off; 199 + 200 + /* 201 + * if this function is called when it is already inited, 202 + * something is wrong 203 + */ 204 + if (bcm_vk_drv_access_ok(vk) && !force_sync) { 205 + dev_err(dev, "Msgq info already in sync\n"); 206 + return -EPERM; 207 + } 208 + 209 + for (i = 0; i < ARRAY_SIZE(chan_list); i++) { 210 + chan = chan_list[i]; 211 + memset(chan->sync_qinfo, 0, sizeof(chan->sync_qinfo)); 212 + 213 + for (j = 0; j < num_q; j++) { 214 + struct bcm_vk_sync_qinfo *qinfo; 215 + u32 msgq_start; 216 + u32 msgq_size; 217 + u32 msgq_nxt; 218 + u32 msgq_db_offset, q_db_offset; 219 + 220 + chan->msgq[j] = msgq; 221 + msgq_start = readl_relaxed(&msgq->start); 222 + msgq_size = readl_relaxed(&msgq->size); 223 + msgq_nxt = readl_relaxed(&msgq->nxt); 224 + msgq_db_offset = readl_relaxed(&msgq->db_offset); 225 + q_db_offset = (msgq_db_offset & ((1 << DB_SHIFT) - 1)); 226 + if (q_db_offset == (~msgq_db_offset >> DB_SHIFT)) 227 + msgq_db_offset = q_db_offset; 228 + else 229 + /* fall back to default */ 230 + msgq_db_offset = VK_BAR0_Q_DB_BASE(j); 231 + 232 + dev_info(dev, 233 + "MsgQ[%d] type %d num %d, @ 0x%x, db_offset 0x%x rd_idx %d wr_idx %d, size %d, nxt 0x%x\n", 234 + j, 235 + readw_relaxed(&msgq->type), 236 + readw_relaxed(&msgq->num), 237 + msgq_start, 238 + msgq_db_offset, 239 + readl_relaxed(&msgq->rd_idx), 240 + readl_relaxed(&msgq->wr_idx), 241 + msgq_size, 242 + msgq_nxt); 243 + 244 + qinfo = &chan->sync_qinfo[j]; 245 + /* formulate and record static info */ 246 + qinfo->q_start = vk->bar[BAR_1] + msgq_start; 247 + qinfo->q_size = msgq_size; 248 + /* set low threshold as 50% or 1/2 */ 249 + qinfo->q_low = qinfo->q_size >> 1; 250 + qinfo->q_mask = qinfo->q_size - 1; 251 + qinfo->q_db_offset = msgq_db_offset; 252 + 253 + msgq++; 254 + } 255 + } 256 + atomic_set(&vk->msgq_inited, 1); 257 + 258 + return ret; 259 + } 260 + 261 + static int bcm_vk_msg_chan_init(struct bcm_vk_msg_chan *chan) 262 + { 263 + u32 i; 264 + 265 + mutex_init(&chan->msgq_mutex); 266 + spin_lock_init(&chan->pendq_lock); 267 + for (i = 0; i < VK_MSGQ_MAX_NR; i++) 268 + INIT_LIST_HEAD(&chan->pendq[i]); 269 + 270 + return 0; 271 + } 272 + 273 + static void bcm_vk_append_pendq(struct bcm_vk_msg_chan *chan, u16 q_num, 274 + struct bcm_vk_wkent *entry) 275 + { 276 + struct bcm_vk_ctx *ctx; 277 + 278 + spin_lock(&chan->pendq_lock); 279 + list_add_tail(&entry->node, &chan->pendq[q_num]); 280 + if (entry->to_h_msg) { 281 + ctx = entry->ctx; 282 + atomic_inc(&ctx->pend_cnt); 283 + wake_up_interruptible(&ctx->rd_wq); 284 + } 285 + spin_unlock(&chan->pendq_lock); 286 + } 287 + 288 + static u32 bcm_vk_append_ib_sgl(struct bcm_vk *vk, 289 + struct bcm_vk_wkent *entry, 290 + struct _vk_data *data, 291 + unsigned int num_planes) 292 + { 293 + unsigned int i; 294 + unsigned int item_cnt = 0; 295 + struct device *dev = &vk->pdev->dev; 296 + struct bcm_vk_msg_chan *chan = &vk->to_v_msg_chan; 297 + struct vk_msg_blk *msg = &entry->to_v_msg[0]; 298 + struct bcm_vk_msgq __iomem *msgq; 299 + struct bcm_vk_sync_qinfo *qinfo; 300 + u32 ib_sgl_size = 0; 301 + u8 *buf = (u8 *)&entry->to_v_msg[entry->to_v_blks]; 302 + u32 avail; 303 + u32 q_num; 304 + 305 + /* check if high watermark is hit, and if so, skip */ 306 + q_num = get_q_num(msg); 307 + msgq = chan->msgq[q_num]; 308 + qinfo = &chan->sync_qinfo[q_num]; 309 + avail = msgq_avail_space(msgq, qinfo); 310 + if (avail < qinfo->q_low) { 311 + dev_dbg(dev, "Skip inserting inband SGL, [0x%x/0x%x]\n", 312 + avail, qinfo->q_size); 313 + return 0; 314 + } 315 + 316 + for (i = 0; i < num_planes; i++) { 317 + if (data[i].address && 318 + (ib_sgl_size + data[i].size) <= vk->ib_sgl_size) { 319 + item_cnt++; 320 + memcpy(buf, entry->dma[i].sglist, data[i].size); 321 + ib_sgl_size += data[i].size; 322 + buf += data[i].size; 323 + } 324 + } 325 + 326 + dev_dbg(dev, "Num %u sgl items appended, size 0x%x, room 0x%x\n", 327 + item_cnt, ib_sgl_size, vk->ib_sgl_size); 328 + 329 + /* round up size */ 330 + ib_sgl_size = (ib_sgl_size + VK_MSGQ_BLK_SIZE - 1) 331 + >> VK_MSGQ_BLK_SZ_SHIFT; 332 + 333 + return ib_sgl_size; 334 + } 335 + 336 + void bcm_to_v_q_doorbell(struct bcm_vk *vk, u32 q_num, u32 db_val) 337 + { 338 + struct bcm_vk_msg_chan *chan = &vk->to_v_msg_chan; 339 + struct bcm_vk_sync_qinfo *qinfo = &chan->sync_qinfo[q_num]; 340 + 341 + vkwrite32(vk, db_val, BAR_0, qinfo->q_db_offset); 342 + } 343 + 344 + static int bcm_to_v_msg_enqueue(struct bcm_vk *vk, struct bcm_vk_wkent *entry) 345 + { 346 + static u32 seq_num; 347 + struct bcm_vk_msg_chan *chan = &vk->to_v_msg_chan; 348 + struct device *dev = &vk->pdev->dev; 349 + struct vk_msg_blk *src = &entry->to_v_msg[0]; 350 + 351 + struct vk_msg_blk __iomem *dst; 352 + struct bcm_vk_msgq __iomem *msgq; 353 + struct bcm_vk_sync_qinfo *qinfo; 354 + u32 q_num = get_q_num(src); 355 + u32 wr_idx; /* local copy */ 356 + u32 i; 357 + u32 avail; 358 + u32 retry; 359 + 360 + if (entry->to_v_blks != src->size + 1) { 361 + dev_err(dev, "number of blks %d not matching %d MsgId[0x%x]: func %d ctx 0x%x\n", 362 + entry->to_v_blks, 363 + src->size + 1, 364 + get_msg_id(src), 365 + src->function_id, 366 + src->context_id); 367 + return -EMSGSIZE; 368 + } 369 + 370 + msgq = chan->msgq[q_num]; 371 + qinfo = &chan->sync_qinfo[q_num]; 372 + 373 + mutex_lock(&chan->msgq_mutex); 374 + 375 + avail = msgq_avail_space(msgq, qinfo); 376 + 377 + /* if not enough space, return EAGAIN and let app handles it */ 378 + retry = 0; 379 + while ((avail < entry->to_v_blks) && 380 + (retry++ < BCM_VK_H2VK_ENQ_RETRY)) { 381 + mutex_unlock(&chan->msgq_mutex); 382 + 383 + msleep(BCM_VK_H2VK_ENQ_RETRY_DELAY_MS); 384 + mutex_lock(&chan->msgq_mutex); 385 + avail = msgq_avail_space(msgq, qinfo); 386 + } 387 + if (retry > BCM_VK_H2VK_ENQ_RETRY) { 388 + mutex_unlock(&chan->msgq_mutex); 389 + return -EAGAIN; 390 + } 391 + 392 + /* at this point, mutex is taken and there is enough space */ 393 + entry->seq_num = seq_num++; /* update debug seq number */ 394 + wr_idx = readl_relaxed(&msgq->wr_idx); 395 + 396 + if (wr_idx >= qinfo->q_size) { 397 + dev_crit(dev, "Invalid wr_idx 0x%x => max 0x%x!", 398 + wr_idx, qinfo->q_size); 399 + bcm_vk_blk_drv_access(vk); 400 + bcm_vk_set_host_alert(vk, ERR_LOG_HOST_PCIE_DWN); 401 + goto idx_err; 402 + } 403 + 404 + dst = msgq_blk_addr(qinfo, wr_idx); 405 + for (i = 0; i < entry->to_v_blks; i++) { 406 + memcpy_toio(dst, src, sizeof(*dst)); 407 + 408 + src++; 409 + wr_idx = msgq_inc(qinfo, wr_idx, 1); 410 + dst = msgq_blk_addr(qinfo, wr_idx); 411 + } 412 + 413 + /* flush the write pointer */ 414 + writel(wr_idx, &msgq->wr_idx); 415 + 416 + /* log new info for debugging */ 417 + dev_dbg(dev, 418 + "MsgQ[%d] [Rd Wr] = [%d %d] blks inserted %d - Q = [u-%d a-%d]/%d\n", 419 + readl_relaxed(&msgq->num), 420 + readl_relaxed(&msgq->rd_idx), 421 + wr_idx, 422 + entry->to_v_blks, 423 + msgq_occupied(msgq, qinfo), 424 + msgq_avail_space(msgq, qinfo), 425 + readl_relaxed(&msgq->size)); 426 + /* 427 + * press door bell based on queue number. 1 is added to the wr_idx 428 + * to avoid the value of 0 appearing on the VK side to distinguish 429 + * from initial value. 430 + */ 431 + bcm_to_v_q_doorbell(vk, q_num, wr_idx + 1); 432 + idx_err: 433 + mutex_unlock(&chan->msgq_mutex); 434 + return 0; 435 + } 436 + 437 + int bcm_vk_send_shutdown_msg(struct bcm_vk *vk, u32 shut_type, 438 + const pid_t pid, const u32 q_num) 439 + { 440 + int rc = 0; 441 + struct bcm_vk_wkent *entry; 442 + struct device *dev = &vk->pdev->dev; 443 + 444 + /* 445 + * check if the marker is still good. Sometimes, the PCIe interface may 446 + * have gone done, and if so and we ship down thing based on broken 447 + * values, kernel may panic. 448 + */ 449 + if (!bcm_vk_msgq_marker_valid(vk)) { 450 + dev_info(dev, "PCIe comm chan - invalid marker (0x%x)!\n", 451 + vkread32(vk, BAR_1, VK_BAR1_MSGQ_DEF_RDY)); 452 + return -EINVAL; 453 + } 454 + 455 + entry = kzalloc(sizeof(*entry) + 456 + sizeof(struct vk_msg_blk), GFP_KERNEL); 457 + if (!entry) 458 + return -ENOMEM; 459 + 460 + /* fill up necessary data */ 461 + entry->to_v_msg[0].function_id = VK_FID_SHUTDOWN; 462 + set_q_num(&entry->to_v_msg[0], q_num); 463 + set_msg_id(&entry->to_v_msg[0], VK_SIMPLEX_MSG_ID); 464 + entry->to_v_blks = 1; /* always 1 block */ 465 + 466 + entry->to_v_msg[0].cmd = shut_type; 467 + entry->to_v_msg[0].arg = pid; 468 + 469 + rc = bcm_to_v_msg_enqueue(vk, entry); 470 + if (rc) 471 + dev_err(dev, 472 + "Sending shutdown message to q %d for pid %d fails.\n", 473 + get_q_num(&entry->to_v_msg[0]), pid); 474 + 475 + kfree(entry); 476 + 477 + return rc; 478 + } 479 + 480 + static int bcm_vk_handle_last_sess(struct bcm_vk *vk, const pid_t pid, 481 + const u32 q_num) 482 + { 483 + int rc = 0; 484 + struct device *dev = &vk->pdev->dev; 485 + 486 + /* 487 + * don't send down or do anything if message queue is not initialized 488 + */ 489 + if (!bcm_vk_drv_access_ok(vk)) 490 + return -EPERM; 491 + 492 + dev_dbg(dev, "No more sessions, shut down pid %d\n", pid); 493 + 494 + rc = bcm_vk_send_shutdown_msg(vk, VK_SHUTDOWN_PID, pid, q_num); 495 + 496 + return rc; 497 + } 498 + 499 + static struct bcm_vk_wkent *bcm_vk_dequeue_pending(struct bcm_vk *vk, 500 + struct bcm_vk_msg_chan *chan, 501 + u16 q_num, 502 + u16 msg_id) 503 + { 504 + bool found = false; 505 + struct bcm_vk_wkent *entry; 506 + 507 + spin_lock(&chan->pendq_lock); 508 + list_for_each_entry(entry, &chan->pendq[q_num], node) { 509 + if (get_msg_id(&entry->to_v_msg[0]) == msg_id) { 510 + list_del(&entry->node); 511 + found = true; 512 + bcm_vk_msgid_bitmap_clear(vk, msg_id, 1); 513 + break; 514 + } 515 + } 516 + spin_unlock(&chan->pendq_lock); 517 + return ((found) ? entry : NULL); 518 + } 519 + 520 + s32 bcm_to_h_msg_dequeue(struct bcm_vk *vk) 521 + { 522 + struct device *dev = &vk->pdev->dev; 523 + struct bcm_vk_msg_chan *chan = &vk->to_h_msg_chan; 524 + struct vk_msg_blk *data; 525 + struct vk_msg_blk __iomem *src; 526 + struct vk_msg_blk *dst; 527 + struct bcm_vk_msgq __iomem *msgq; 528 + struct bcm_vk_sync_qinfo *qinfo; 529 + struct bcm_vk_wkent *entry; 530 + u32 rd_idx, wr_idx; 531 + u32 q_num, msg_id, j; 532 + u32 num_blks; 533 + s32 total = 0; 534 + int cnt = 0; 535 + int msg_processed = 0; 536 + int max_msg_to_process; 537 + bool exit_loop; 538 + 539 + /* 540 + * drain all the messages from the queues, and find its pending 541 + * entry in the to_v queue, based on msg_id & q_num, and move the 542 + * entry to the to_h pending queue, waiting for user space 543 + * program to extract 544 + */ 545 + mutex_lock(&chan->msgq_mutex); 546 + 547 + for (q_num = 0; q_num < chan->q_nr; q_num++) { 548 + msgq = chan->msgq[q_num]; 549 + qinfo = &chan->sync_qinfo[q_num]; 550 + max_msg_to_process = BCM_VK_MSG_PROC_MAX_LOOP * qinfo->q_size; 551 + 552 + rd_idx = readl_relaxed(&msgq->rd_idx); 553 + wr_idx = readl_relaxed(&msgq->wr_idx); 554 + msg_processed = 0; 555 + exit_loop = false; 556 + while ((rd_idx != wr_idx) && !exit_loop) { 557 + u8 src_size; 558 + 559 + /* 560 + * Make a local copy and get pointer to src blk 561 + * The rd_idx is masked before getting the pointer to 562 + * avoid out of bound access in case the interface goes 563 + * down. It will end up pointing to the last block in 564 + * the buffer, but subsequent src->size check would be 565 + * able to catch this. 566 + */ 567 + src = msgq_blk_addr(qinfo, rd_idx & qinfo->q_mask); 568 + src_size = readb(&src->size); 569 + 570 + if ((rd_idx >= qinfo->q_size) || 571 + (src_size > (qinfo->q_size - 1))) { 572 + dev_crit(dev, 573 + "Invalid rd_idx 0x%x or size 0x%x => max 0x%x!", 574 + rd_idx, src_size, qinfo->q_size); 575 + bcm_vk_blk_drv_access(vk); 576 + bcm_vk_set_host_alert(vk, 577 + ERR_LOG_HOST_PCIE_DWN); 578 + goto idx_err; 579 + } 580 + 581 + num_blks = src_size + 1; 582 + data = kzalloc(num_blks * VK_MSGQ_BLK_SIZE, GFP_KERNEL); 583 + if (data) { 584 + /* copy messages and linearize it */ 585 + dst = data; 586 + for (j = 0; j < num_blks; j++) { 587 + memcpy_fromio(dst, src, sizeof(*dst)); 588 + 589 + dst++; 590 + rd_idx = msgq_inc(qinfo, rd_idx, 1); 591 + src = msgq_blk_addr(qinfo, rd_idx); 592 + } 593 + total++; 594 + } else { 595 + /* 596 + * if we could not allocate memory in kernel, 597 + * that is fatal. 598 + */ 599 + dev_crit(dev, "Kernel mem allocation failure.\n"); 600 + return -ENOMEM; 601 + } 602 + 603 + /* flush rd pointer after a message is dequeued */ 604 + writel(rd_idx, &msgq->rd_idx); 605 + 606 + /* log new info for debugging */ 607 + dev_dbg(dev, 608 + "MsgQ[%d] [Rd Wr] = [%d %d] blks extracted %d - Q = [u-%d a-%d]/%d\n", 609 + readl_relaxed(&msgq->num), 610 + rd_idx, 611 + wr_idx, 612 + num_blks, 613 + msgq_occupied(msgq, qinfo), 614 + msgq_avail_space(msgq, qinfo), 615 + readl_relaxed(&msgq->size)); 616 + 617 + /* 618 + * No need to search if it is an autonomous one-way 619 + * message from driver, as these messages do not bear 620 + * a to_v pending item. Currently, only the shutdown 621 + * message falls into this category. 622 + */ 623 + if (data->function_id == VK_FID_SHUTDOWN) { 624 + kfree(data); 625 + continue; 626 + } 627 + 628 + msg_id = get_msg_id(data); 629 + /* lookup original message in to_v direction */ 630 + entry = bcm_vk_dequeue_pending(vk, 631 + &vk->to_v_msg_chan, 632 + q_num, 633 + msg_id); 634 + 635 + /* 636 + * if there is message to does not have prior send, 637 + * this is the location to add here 638 + */ 639 + if (entry) { 640 + entry->to_h_blks = num_blks; 641 + entry->to_h_msg = data; 642 + bcm_vk_append_pendq(&vk->to_h_msg_chan, 643 + q_num, entry); 644 + 645 + } else { 646 + if (cnt++ < batch_log) 647 + dev_info(dev, 648 + "Could not find MsgId[0x%x] for resp func %d bmap %d\n", 649 + msg_id, data->function_id, 650 + test_bit(msg_id, vk->bmap)); 651 + kfree(data); 652 + } 653 + /* Fetch wr_idx to handle more back-to-back events */ 654 + wr_idx = readl(&msgq->wr_idx); 655 + 656 + /* 657 + * cap the max so that even we try to handle more back-to-back events, 658 + * so that it won't hold CPU too long or in case rd/wr idexes are 659 + * corrupted which triggers infinite looping. 660 + */ 661 + if (++msg_processed >= max_msg_to_process) { 662 + dev_warn(dev, "Q[%d] Per loop processing exceeds %d\n", 663 + q_num, max_msg_to_process); 664 + exit_loop = true; 665 + } 666 + } 667 + } 668 + idx_err: 669 + mutex_unlock(&chan->msgq_mutex); 670 + dev_dbg(dev, "total %d drained from queues\n", total); 671 + 672 + return total; 673 + } 674 + 675 + /* 676 + * init routine for all required data structures 677 + */ 678 + static int bcm_vk_data_init(struct bcm_vk *vk) 679 + { 680 + int i; 681 + 682 + spin_lock_init(&vk->ctx_lock); 683 + for (i = 0; i < ARRAY_SIZE(vk->ctx); i++) { 684 + vk->ctx[i].in_use = false; 685 + vk->ctx[i].idx = i; /* self identity */ 686 + vk->ctx[i].miscdev = NULL; 687 + } 688 + spin_lock_init(&vk->msg_id_lock); 689 + spin_lock_init(&vk->host_alert_lock); 690 + vk->msg_id = 0; 691 + 692 + /* initialize hash table */ 693 + for (i = 0; i < VK_PID_HT_SZ; i++) 694 + INIT_LIST_HEAD(&vk->pid_ht[i].head); 695 + 696 + return 0; 697 + } 698 + 699 + irqreturn_t bcm_vk_msgq_irqhandler(int irq, void *dev_id) 700 + { 701 + struct bcm_vk *vk = dev_id; 702 + 703 + if (!bcm_vk_drv_access_ok(vk)) { 704 + dev_err(&vk->pdev->dev, 705 + "Interrupt %d received when msgq not inited\n", irq); 706 + goto skip_schedule_work; 707 + } 708 + 709 + queue_work(vk->wq_thread, &vk->wq_work); 710 + 711 + skip_schedule_work: 712 + return IRQ_HANDLED; 713 + } 714 + 312 715 int bcm_vk_open(struct inode *inode, struct file *p_file) 313 716 { 314 717 struct bcm_vk_ctx *ctx; ··· 969 112 return rc; 970 113 } 971 114 115 + ssize_t bcm_vk_read(struct file *p_file, 116 + char __user *buf, 117 + size_t count, 118 + loff_t *f_pos) 119 + { 120 + ssize_t rc = -ENOMSG; 121 + struct bcm_vk_ctx *ctx = p_file->private_data; 122 + struct bcm_vk *vk = container_of(ctx->miscdev, struct bcm_vk, 123 + miscdev); 124 + struct device *dev = &vk->pdev->dev; 125 + struct bcm_vk_msg_chan *chan = &vk->to_h_msg_chan; 126 + struct bcm_vk_wkent *entry = NULL; 127 + u32 q_num; 128 + u32 rsp_length; 129 + bool found = false; 130 + 131 + if (!bcm_vk_drv_access_ok(vk)) 132 + return -EPERM; 133 + 134 + dev_dbg(dev, "Buf count %zu\n", count); 135 + found = false; 136 + 137 + /* 138 + * search through the pendq on the to_h chan, and return only those 139 + * that belongs to the same context. Search is always from the high to 140 + * the low priority queues 141 + */ 142 + spin_lock(&chan->pendq_lock); 143 + for (q_num = 0; q_num < chan->q_nr; q_num++) { 144 + list_for_each_entry(entry, &chan->pendq[q_num], node) { 145 + if (entry->ctx->idx == ctx->idx) { 146 + if (count >= 147 + (entry->to_h_blks * VK_MSGQ_BLK_SIZE)) { 148 + list_del(&entry->node); 149 + atomic_dec(&ctx->pend_cnt); 150 + found = true; 151 + } else { 152 + /* buffer not big enough */ 153 + rc = -EMSGSIZE; 154 + } 155 + goto read_loop_exit; 156 + } 157 + } 158 + } 159 + read_loop_exit: 160 + spin_unlock(&chan->pendq_lock); 161 + 162 + if (found) { 163 + /* retrieve the passed down msg_id */ 164 + set_msg_id(&entry->to_h_msg[0], entry->usr_msg_id); 165 + rsp_length = entry->to_h_blks * VK_MSGQ_BLK_SIZE; 166 + if (copy_to_user(buf, entry->to_h_msg, rsp_length) == 0) 167 + rc = rsp_length; 168 + 169 + bcm_vk_free_wkent(dev, entry); 170 + } else if (rc == -EMSGSIZE) { 171 + struct vk_msg_blk tmp_msg = entry->to_h_msg[0]; 172 + 173 + /* 174 + * in this case, return just the first block, so 175 + * that app knows what size it is looking for. 176 + */ 177 + set_msg_id(&tmp_msg, entry->usr_msg_id); 178 + tmp_msg.size = entry->to_h_blks - 1; 179 + if (copy_to_user(buf, &tmp_msg, VK_MSGQ_BLK_SIZE) != 0) { 180 + dev_err(dev, "Error return 1st block in -EMSGSIZE\n"); 181 + rc = -EFAULT; 182 + } 183 + } 184 + return rc; 185 + } 186 + 187 + ssize_t bcm_vk_write(struct file *p_file, 188 + const char __user *buf, 189 + size_t count, 190 + loff_t *f_pos) 191 + { 192 + ssize_t rc; 193 + struct bcm_vk_ctx *ctx = p_file->private_data; 194 + struct bcm_vk *vk = container_of(ctx->miscdev, struct bcm_vk, 195 + miscdev); 196 + struct bcm_vk_msgq __iomem *msgq; 197 + struct device *dev = &vk->pdev->dev; 198 + struct bcm_vk_wkent *entry; 199 + u32 sgl_extra_blks; 200 + u32 q_num; 201 + u32 msg_size; 202 + u32 msgq_size; 203 + 204 + if (!bcm_vk_drv_access_ok(vk)) 205 + return -EPERM; 206 + 207 + dev_dbg(dev, "Msg count %zu\n", count); 208 + 209 + /* first, do sanity check where count should be multiple of basic blk */ 210 + if (count & (VK_MSGQ_BLK_SIZE - 1)) { 211 + dev_err(dev, "Failure with size %zu not multiple of %zu\n", 212 + count, VK_MSGQ_BLK_SIZE); 213 + rc = -EINVAL; 214 + goto write_err; 215 + } 216 + 217 + /* allocate the work entry + buffer for size count and inband sgl */ 218 + entry = kzalloc(sizeof(*entry) + count + vk->ib_sgl_size, 219 + GFP_KERNEL); 220 + if (!entry) { 221 + rc = -ENOMEM; 222 + goto write_err; 223 + } 224 + 225 + /* now copy msg from user space, and then formulate the work entry */ 226 + if (copy_from_user(&entry->to_v_msg[0], buf, count)) { 227 + rc = -EFAULT; 228 + goto write_free_ent; 229 + } 230 + 231 + entry->to_v_blks = count >> VK_MSGQ_BLK_SZ_SHIFT; 232 + entry->ctx = ctx; 233 + 234 + /* do a check on the blk size which could not exceed queue space */ 235 + q_num = get_q_num(&entry->to_v_msg[0]); 236 + msgq = vk->to_v_msg_chan.msgq[q_num]; 237 + msgq_size = readl_relaxed(&msgq->size); 238 + if (entry->to_v_blks + (vk->ib_sgl_size >> VK_MSGQ_BLK_SZ_SHIFT) 239 + > (msgq_size - 1)) { 240 + dev_err(dev, "Blk size %d exceed max queue size allowed %d\n", 241 + entry->to_v_blks, msgq_size - 1); 242 + rc = -EINVAL; 243 + goto write_free_ent; 244 + } 245 + 246 + /* Use internal message id */ 247 + entry->usr_msg_id = get_msg_id(&entry->to_v_msg[0]); 248 + rc = bcm_vk_get_msg_id(vk); 249 + if (rc == VK_MSG_ID_OVERFLOW) { 250 + dev_err(dev, "msg_id overflow\n"); 251 + rc = -EOVERFLOW; 252 + goto write_free_ent; 253 + } 254 + set_msg_id(&entry->to_v_msg[0], rc); 255 + ctx->q_num = q_num; 256 + 257 + dev_dbg(dev, 258 + "[Q-%d]Message ctx id %d, usr_msg_id 0x%x sent msg_id 0x%x\n", 259 + ctx->q_num, ctx->idx, entry->usr_msg_id, 260 + get_msg_id(&entry->to_v_msg[0])); 261 + 262 + if (entry->to_v_msg[0].function_id == VK_FID_TRANS_BUF) { 263 + /* Convert any pointers to sg list */ 264 + unsigned int num_planes; 265 + int dir; 266 + struct _vk_data *data; 267 + 268 + num_planes = entry->to_v_msg[0].cmd & VK_CMD_PLANES_MASK; 269 + if ((entry->to_v_msg[0].cmd & VK_CMD_MASK) == VK_CMD_DOWNLOAD) 270 + dir = DMA_FROM_DEVICE; 271 + else 272 + dir = DMA_TO_DEVICE; 273 + 274 + /* Calculate vk_data location */ 275 + /* Go to end of the message */ 276 + msg_size = entry->to_v_msg[0].size; 277 + if (msg_size > entry->to_v_blks) { 278 + rc = -EMSGSIZE; 279 + goto write_free_msgid; 280 + } 281 + 282 + data = (struct _vk_data *)&entry->to_v_msg[msg_size + 1]; 283 + 284 + /* Now back up to the start of the pointers */ 285 + data -= num_planes; 286 + 287 + /* Convert user addresses to DMA SG List */ 288 + rc = bcm_vk_sg_alloc(dev, entry->dma, dir, data, num_planes); 289 + if (rc) 290 + goto write_free_msgid; 291 + 292 + atomic_inc(&ctx->dma_cnt); 293 + /* try to embed inband sgl */ 294 + sgl_extra_blks = bcm_vk_append_ib_sgl(vk, entry, data, 295 + num_planes); 296 + entry->to_v_blks += sgl_extra_blks; 297 + entry->to_v_msg[0].size += sgl_extra_blks; 298 + } else if (entry->to_v_msg[0].function_id == VK_FID_INIT && 299 + entry->to_v_msg[0].context_id == VK_NEW_CTX) { 300 + /* 301 + * Init happens in 2 stages, only the first stage contains the 302 + * pid that needs translating. 303 + */ 304 + pid_t org_pid, pid; 305 + 306 + /* 307 + * translate the pid into the unique host space as user 308 + * may run sessions inside containers or process 309 + * namespaces. 310 + */ 311 + #define VK_MSG_PID_MASK 0xffffff00 312 + #define VK_MSG_PID_SH 8 313 + org_pid = (entry->to_v_msg[0].arg & VK_MSG_PID_MASK) 314 + >> VK_MSG_PID_SH; 315 + 316 + pid = task_tgid_nr(current); 317 + entry->to_v_msg[0].arg = 318 + (entry->to_v_msg[0].arg & ~VK_MSG_PID_MASK) | 319 + (pid << VK_MSG_PID_SH); 320 + if (org_pid != pid) 321 + dev_dbg(dev, "In PID 0x%x(%d), converted PID 0x%x(%d)\n", 322 + org_pid, org_pid, pid, pid); 323 + } 324 + 325 + /* 326 + * store work entry to pending queue until a response is received. 327 + * This needs to be done before enqueuing the message 328 + */ 329 + bcm_vk_append_pendq(&vk->to_v_msg_chan, q_num, entry); 330 + 331 + rc = bcm_to_v_msg_enqueue(vk, entry); 332 + if (rc) { 333 + dev_err(dev, "Fail to enqueue msg to to_v queue\n"); 334 + 335 + /* remove message from pending list */ 336 + entry = bcm_vk_dequeue_pending 337 + (vk, 338 + &vk->to_v_msg_chan, 339 + q_num, 340 + get_msg_id(&entry->to_v_msg[0])); 341 + goto write_free_ent; 342 + } 343 + 344 + return count; 345 + 346 + write_free_msgid: 347 + bcm_vk_msgid_bitmap_clear(vk, get_msg_id(&entry->to_v_msg[0]), 1); 348 + write_free_ent: 349 + kfree(entry); 350 + write_err: 351 + return rc; 352 + } 353 + 354 + __poll_t bcm_vk_poll(struct file *p_file, struct poll_table_struct *wait) 355 + { 356 + __poll_t ret = 0; 357 + int cnt; 358 + struct bcm_vk_ctx *ctx = p_file->private_data; 359 + struct bcm_vk *vk = container_of(ctx->miscdev, struct bcm_vk, miscdev); 360 + struct device *dev = &vk->pdev->dev; 361 + 362 + poll_wait(p_file, &ctx->rd_wq, wait); 363 + 364 + cnt = atomic_read(&ctx->pend_cnt); 365 + if (cnt) { 366 + ret = (__force __poll_t)(POLLIN | POLLRDNORM); 367 + if (cnt < 0) { 368 + dev_err(dev, "Error cnt %d, setting back to 0", cnt); 369 + atomic_set(&ctx->pend_cnt, 0); 370 + } 371 + } 372 + 373 + return ret; 374 + } 375 + 972 376 int bcm_vk_release(struct inode *inode, struct file *p_file) 973 377 { 974 378 int ret; 975 379 struct bcm_vk_ctx *ctx = p_file->private_data; 976 380 struct bcm_vk *vk = container_of(ctx->miscdev, struct bcm_vk, miscdev); 381 + struct device *dev = &vk->pdev->dev; 382 + pid_t pid = ctx->pid; 383 + int dma_cnt; 384 + unsigned long timeout, start_time; 385 + 386 + /* 387 + * if there are outstanding DMA transactions, need to delay long enough 388 + * to ensure that the card side would have stopped touching the host buffer 389 + * and its SGL list. A race condition could happen if the host app is killed 390 + * abruptly, eg kill -9, while some DMA transfer orders are still inflight. 391 + * Nothing could be done except for a delay as host side is running in a 392 + * completely async fashion. 393 + */ 394 + start_time = jiffies; 395 + timeout = start_time + msecs_to_jiffies(BCM_VK_DMA_DRAIN_MAX_MS); 396 + do { 397 + if (time_after(jiffies, timeout)) { 398 + dev_warn(dev, "%d dma still pending for [fd-%d] pid %d\n", 399 + dma_cnt, ctx->idx, pid); 400 + break; 401 + } 402 + dma_cnt = atomic_read(&ctx->dma_cnt); 403 + cpu_relax(); 404 + cond_resched(); 405 + } while (dma_cnt); 406 + dev_dbg(dev, "Draining for [fd-%d] pid %d - delay %d ms\n", 407 + ctx->idx, pid, jiffies_to_msecs(jiffies - start_time)); 408 + 409 + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_v_msg_chan, ctx); 410 + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_h_msg_chan, ctx); 977 411 978 412 ret = bcm_vk_free_ctx(vk, ctx); 413 + if (ret == 0) 414 + ret = bcm_vk_handle_last_sess(vk, pid, ctx->q_num); 415 + else 416 + ret = 0; 979 417 980 418 kref_put(&vk->kref, bcm_vk_release_data); 981 419 982 420 return ret; 421 + } 422 + 423 + int bcm_vk_msg_init(struct bcm_vk *vk) 424 + { 425 + struct device *dev = &vk->pdev->dev; 426 + int ret; 427 + 428 + if (bcm_vk_data_init(vk)) { 429 + dev_err(dev, "Error initializing internal data structures\n"); 430 + return -EINVAL; 431 + } 432 + 433 + if (bcm_vk_msg_chan_init(&vk->to_v_msg_chan) || 434 + bcm_vk_msg_chan_init(&vk->to_h_msg_chan)) { 435 + dev_err(dev, "Error initializing communication channel\n"); 436 + return -EIO; 437 + } 438 + 439 + /* read msgq info if ready */ 440 + ret = bcm_vk_sync_msgq(vk, false); 441 + if (ret && (ret != -EAGAIN)) { 442 + dev_err(dev, "Error reading comm msg Q info\n"); 443 + return -EIO; 444 + } 445 + 446 + return 0; 447 + } 448 + 449 + void bcm_vk_msg_remove(struct bcm_vk *vk) 450 + { 451 + bcm_vk_blk_drv_access(vk); 452 + 453 + /* drain all pending items */ 454 + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_v_msg_chan, NULL); 455 + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_h_msg_chan, NULL); 983 456 } 984 457
+132
drivers/misc/bcm-vk/bcm_vk_msg.h
··· 6 6 #ifndef BCM_VK_MSG_H 7 7 #define BCM_VK_MSG_H 8 8 9 + #include <uapi/linux/misc/bcm_vk.h> 10 + #include "bcm_vk_sg.h" 11 + 12 + /* Single message queue control structure */ 13 + struct bcm_vk_msgq { 14 + u16 type; /* queue type */ 15 + u16 num; /* queue number */ 16 + u32 start; /* offset in BAR1 where the queue memory starts */ 17 + 18 + u32 rd_idx; /* read idx */ 19 + u32 wr_idx; /* write idx */ 20 + 21 + u32 size; /* 22 + * size, which is in number of 16byte blocks, 23 + * to align with the message data structure. 24 + */ 25 + u32 nxt; /* 26 + * nxt offset to the next msg queue struct. 27 + * This is to provide flexibity for alignment purposes. 28 + */ 29 + 30 + /* Least significant 16 bits in below field hold doorbell register offset */ 31 + #define DB_SHIFT 16 32 + 33 + u32 db_offset; /* queue doorbell register offset in BAR0 */ 34 + 35 + u32 rsvd; 36 + }; 37 + 38 + /* 39 + * Structure to record static info from the msgq sync. We keep local copy 40 + * for some of these variables for both performance + checking purpose. 41 + */ 42 + struct bcm_vk_sync_qinfo { 43 + void __iomem *q_start; 44 + u32 q_size; 45 + u32 q_mask; 46 + u32 q_low; 47 + u32 q_db_offset; 48 + }; 49 + 50 + #define VK_MSGQ_MAX_NR 4 /* Maximum number of message queues */ 51 + 52 + /* 53 + * message block - basic unit in the message where a message's size is always 54 + * N x sizeof(basic_block) 55 + */ 56 + struct vk_msg_blk { 57 + u8 function_id; 58 + #define VK_FID_TRANS_BUF 5 59 + #define VK_FID_SHUTDOWN 8 60 + #define VK_FID_INIT 9 61 + u8 size; /* size of the message in number of vk_msg_blk's */ 62 + u16 trans_id; /* transport id, queue & msg_id */ 63 + u32 context_id; 64 + #define VK_NEW_CTX 0 65 + u32 cmd; 66 + #define VK_CMD_PLANES_MASK 0x000f /* number of planes to up/download */ 67 + #define VK_CMD_UPLOAD 0x0400 /* memory transfer to vk */ 68 + #define VK_CMD_DOWNLOAD 0x0500 /* memory transfer from vk */ 69 + #define VK_CMD_MASK 0x0f00 /* command mask */ 70 + u32 arg; 71 + }; 72 + 73 + /* vk_msg_blk is 16 bytes fixed */ 74 + #define VK_MSGQ_BLK_SIZE (sizeof(struct vk_msg_blk)) 75 + /* shift for fast division of basic msg blk size */ 76 + #define VK_MSGQ_BLK_SZ_SHIFT 4 77 + 78 + /* use msg_id 0 for any simplex host2vk communication */ 79 + #define VK_SIMPLEX_MSG_ID 0 80 + 9 81 /* context per session opening of sysfs */ 10 82 struct bcm_vk_ctx { 11 83 struct list_head node; /* use for linkage in Hash Table */ ··· 85 13 bool in_use; 86 14 pid_t pid; 87 15 u32 hash_idx; 16 + u32 q_num; /* queue number used by the stream */ 88 17 struct miscdevice *miscdev; 18 + atomic_t pend_cnt; /* number of items pending to be read from host */ 19 + atomic_t dma_cnt; /* any dma transaction outstanding */ 20 + wait_queue_head_t rd_wq; 89 21 }; 90 22 91 23 /* pid hash table entry */ ··· 97 21 struct list_head head; 98 22 }; 99 23 24 + #define VK_DMA_MAX_ADDRS 4 /* Max 4 DMA Addresses */ 25 + /* structure for house keeping a single work entry */ 26 + struct bcm_vk_wkent { 27 + struct list_head node; /* for linking purpose */ 28 + struct bcm_vk_ctx *ctx; 29 + 30 + /* Store up to 4 dma pointers */ 31 + struct bcm_vk_dma dma[VK_DMA_MAX_ADDRS]; 32 + 33 + u32 to_h_blks; /* response */ 34 + struct vk_msg_blk *to_h_msg; 35 + 36 + /* 37 + * put the to_v_msg at the end so that we could simply append to_v msg 38 + * to the end of the allocated block 39 + */ 40 + u32 usr_msg_id; 41 + u32 to_v_blks; 42 + u32 seq_num; 43 + struct vk_msg_blk to_v_msg[0]; 44 + }; 45 + 46 + /* queue stats counters */ 47 + struct bcm_vk_qs_cnts { 48 + u32 cnt; /* general counter, used to limit output */ 49 + u32 acc_sum; 50 + u32 max_occ; /* max during a sampling period */ 51 + u32 max_abs; /* the abs max since reset */ 52 + }; 53 + 54 + /* control channel structure for either to_v or to_h communication */ 55 + struct bcm_vk_msg_chan { 56 + u32 q_nr; 57 + /* Mutex to access msgq */ 58 + struct mutex msgq_mutex; 59 + /* pointing to BAR locations */ 60 + struct bcm_vk_msgq __iomem *msgq[VK_MSGQ_MAX_NR]; 61 + /* Spinlock to access pending queue */ 62 + spinlock_t pendq_lock; 63 + /* for temporary storing pending items, one for each queue */ 64 + struct list_head pendq[VK_MSGQ_MAX_NR]; 65 + /* static queue info from the sync */ 66 + struct bcm_vk_sync_qinfo sync_qinfo[VK_MSGQ_MAX_NR]; 67 + }; 68 + 69 + /* totol number of message q allowed by the driver */ 70 + #define VK_MSGQ_PER_CHAN_MAX 3 71 + #define VK_MSGQ_NUM_DEFAULT (VK_MSGQ_PER_CHAN_MAX - 1) 72 + 100 73 /* total number of supported ctx, 32 ctx each for 5 components */ 101 74 #define VK_CMPT_CTX_MAX (32 * 5) 102 75 103 76 /* hash table defines to store the opened FDs */ 104 77 #define VK_PID_HT_SHIFT_BIT 7 /* 128 */ 105 78 #define VK_PID_HT_SZ BIT(VK_PID_HT_SHIFT_BIT) 79 + 80 + /* The following are offsets of DDR info provided by the vk card */ 81 + #define VK_BAR0_SEG_SIZE (4 * SZ_1K) /* segment size for BAR0 */ 82 + 83 + /* shutdown types supported */ 84 + #define VK_SHUTDOWN_PID 1 85 + #define VK_SHUTDOWN_GRACEFUL 2 106 86 107 87 #endif
+275
drivers/misc/bcm-vk/bcm_vk_sg.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2018-2020 Broadcom. 4 + */ 5 + #include <linux/dma-mapping.h> 6 + #include <linux/mm.h> 7 + #include <linux/pagemap.h> 8 + #include <linux/pgtable.h> 9 + #include <linux/vmalloc.h> 10 + 11 + #include <asm/page.h> 12 + #include <asm/unaligned.h> 13 + 14 + #include <uapi/linux/misc/bcm_vk.h> 15 + 16 + #include "bcm_vk.h" 17 + #include "bcm_vk_msg.h" 18 + #include "bcm_vk_sg.h" 19 + 20 + /* 21 + * Valkyrie has a hardware limitation of 16M transfer size. 22 + * So limit the SGL chunks to 16M. 23 + */ 24 + #define BCM_VK_MAX_SGL_CHUNK SZ_16M 25 + 26 + static int bcm_vk_dma_alloc(struct device *dev, 27 + struct bcm_vk_dma *dma, 28 + int dir, 29 + struct _vk_data *vkdata); 30 + static int bcm_vk_dma_free(struct device *dev, struct bcm_vk_dma *dma); 31 + 32 + /* Uncomment to dump SGLIST */ 33 + /* #define BCM_VK_DUMP_SGLIST */ 34 + 35 + static int bcm_vk_dma_alloc(struct device *dev, 36 + struct bcm_vk_dma *dma, 37 + int direction, 38 + struct _vk_data *vkdata) 39 + { 40 + dma_addr_t addr, sg_addr; 41 + int err; 42 + int i; 43 + int offset; 44 + u32 size; 45 + u32 remaining_size; 46 + u32 transfer_size; 47 + u64 data; 48 + unsigned long first, last; 49 + struct _vk_data *sgdata; 50 + 51 + /* Get 64-bit user address */ 52 + data = get_unaligned(&vkdata->address); 53 + 54 + /* offset into first page */ 55 + offset = offset_in_page(data); 56 + 57 + /* Calculate number of pages */ 58 + first = (data & PAGE_MASK) >> PAGE_SHIFT; 59 + last = ((data + vkdata->size - 1) & PAGE_MASK) >> PAGE_SHIFT; 60 + dma->nr_pages = last - first + 1; 61 + 62 + /* Allocate DMA pages */ 63 + dma->pages = kmalloc_array(dma->nr_pages, 64 + sizeof(struct page *), 65 + GFP_KERNEL); 66 + if (!dma->pages) 67 + return -ENOMEM; 68 + 69 + dev_dbg(dev, "Alloc DMA Pages [0x%llx+0x%x => %d pages]\n", 70 + data, vkdata->size, dma->nr_pages); 71 + 72 + dma->direction = direction; 73 + 74 + /* Get user pages into memory */ 75 + err = get_user_pages_fast(data & PAGE_MASK, 76 + dma->nr_pages, 77 + direction == DMA_FROM_DEVICE, 78 + dma->pages); 79 + if (err != dma->nr_pages) { 80 + dma->nr_pages = (err >= 0) ? err : 0; 81 + dev_err(dev, "get_user_pages_fast, err=%d [%d]\n", 82 + err, dma->nr_pages); 83 + return err < 0 ? err : -EINVAL; 84 + } 85 + 86 + /* Max size of sg list is 1 per mapped page + fields at start */ 87 + dma->sglen = (dma->nr_pages * sizeof(*sgdata)) + 88 + (sizeof(u32) * SGLIST_VKDATA_START); 89 + 90 + /* Allocate sglist */ 91 + dma->sglist = dma_alloc_coherent(dev, 92 + dma->sglen, 93 + &dma->handle, 94 + GFP_KERNEL); 95 + if (!dma->sglist) 96 + return -ENOMEM; 97 + 98 + dma->sglist[SGLIST_NUM_SG] = 0; 99 + dma->sglist[SGLIST_TOTALSIZE] = vkdata->size; 100 + remaining_size = vkdata->size; 101 + sgdata = (struct _vk_data *)&dma->sglist[SGLIST_VKDATA_START]; 102 + 103 + /* Map all pages into DMA */ 104 + size = min_t(size_t, PAGE_SIZE - offset, remaining_size); 105 + remaining_size -= size; 106 + sg_addr = dma_map_page(dev, 107 + dma->pages[0], 108 + offset, 109 + size, 110 + dma->direction); 111 + transfer_size = size; 112 + if (unlikely(dma_mapping_error(dev, sg_addr))) { 113 + __free_page(dma->pages[0]); 114 + return -EIO; 115 + } 116 + 117 + for (i = 1; i < dma->nr_pages; i++) { 118 + size = min_t(size_t, PAGE_SIZE, remaining_size); 119 + remaining_size -= size; 120 + addr = dma_map_page(dev, 121 + dma->pages[i], 122 + 0, 123 + size, 124 + dma->direction); 125 + if (unlikely(dma_mapping_error(dev, addr))) { 126 + __free_page(dma->pages[i]); 127 + return -EIO; 128 + } 129 + 130 + /* 131 + * Compress SG list entry when pages are contiguous 132 + * and transfer size less or equal to BCM_VK_MAX_SGL_CHUNK 133 + */ 134 + if ((addr == (sg_addr + transfer_size)) && 135 + ((transfer_size + size) <= BCM_VK_MAX_SGL_CHUNK)) { 136 + /* pages are contiguous, add to same sg entry */ 137 + transfer_size += size; 138 + } else { 139 + /* pages are not contiguous, write sg entry */ 140 + sgdata->size = transfer_size; 141 + put_unaligned(sg_addr, (u64 *)&sgdata->address); 142 + dma->sglist[SGLIST_NUM_SG]++; 143 + 144 + /* start new sg entry */ 145 + sgdata++; 146 + sg_addr = addr; 147 + transfer_size = size; 148 + } 149 + } 150 + /* Write last sg list entry */ 151 + sgdata->size = transfer_size; 152 + put_unaligned(sg_addr, (u64 *)&sgdata->address); 153 + dma->sglist[SGLIST_NUM_SG]++; 154 + 155 + /* Update pointers and size field to point to sglist */ 156 + put_unaligned((u64)dma->handle, &vkdata->address); 157 + vkdata->size = (dma->sglist[SGLIST_NUM_SG] * sizeof(*sgdata)) + 158 + (sizeof(u32) * SGLIST_VKDATA_START); 159 + 160 + #ifdef BCM_VK_DUMP_SGLIST 161 + dev_dbg(dev, 162 + "sgl 0x%llx handle 0x%llx, sglen: 0x%x sgsize: 0x%x\n", 163 + (u64)dma->sglist, 164 + dma->handle, 165 + dma->sglen, 166 + vkdata->size); 167 + for (i = 0; i < vkdata->size / sizeof(u32); i++) 168 + dev_dbg(dev, "i:0x%x 0x%x\n", i, dma->sglist[i]); 169 + #endif 170 + 171 + return 0; 172 + } 173 + 174 + int bcm_vk_sg_alloc(struct device *dev, 175 + struct bcm_vk_dma *dma, 176 + int dir, 177 + struct _vk_data *vkdata, 178 + int num) 179 + { 180 + int i; 181 + int rc = -EINVAL; 182 + 183 + /* Convert user addresses to DMA SG List */ 184 + for (i = 0; i < num; i++) { 185 + if (vkdata[i].size && vkdata[i].address) { 186 + /* 187 + * If both size and address are non-zero 188 + * then DMA alloc. 189 + */ 190 + rc = bcm_vk_dma_alloc(dev, 191 + &dma[i], 192 + dir, 193 + &vkdata[i]); 194 + } else if (vkdata[i].size || 195 + vkdata[i].address) { 196 + /* 197 + * If one of size and address are zero 198 + * there is a problem. 199 + */ 200 + dev_err(dev, 201 + "Invalid vkdata %x 0x%x 0x%llx\n", 202 + i, vkdata[i].size, vkdata[i].address); 203 + rc = -EINVAL; 204 + } else { 205 + /* 206 + * If size and address are both zero 207 + * don't convert, but return success. 208 + */ 209 + rc = 0; 210 + } 211 + 212 + if (rc) 213 + goto fail_alloc; 214 + } 215 + return rc; 216 + 217 + fail_alloc: 218 + while (i > 0) { 219 + i--; 220 + if (dma[i].sglist) 221 + bcm_vk_dma_free(dev, &dma[i]); 222 + } 223 + return rc; 224 + } 225 + 226 + static int bcm_vk_dma_free(struct device *dev, struct bcm_vk_dma *dma) 227 + { 228 + dma_addr_t addr; 229 + int i; 230 + int num_sg; 231 + u32 size; 232 + struct _vk_data *vkdata; 233 + 234 + dev_dbg(dev, "free sglist=%p sglen=0x%x\n", dma->sglist, dma->sglen); 235 + 236 + /* Unmap all pages in the sglist */ 237 + num_sg = dma->sglist[SGLIST_NUM_SG]; 238 + vkdata = (struct _vk_data *)&dma->sglist[SGLIST_VKDATA_START]; 239 + for (i = 0; i < num_sg; i++) { 240 + size = vkdata[i].size; 241 + addr = get_unaligned(&vkdata[i].address); 242 + 243 + dma_unmap_page(dev, addr, size, dma->direction); 244 + } 245 + 246 + /* Free allocated sglist */ 247 + dma_free_coherent(dev, dma->sglen, dma->sglist, dma->handle); 248 + 249 + /* Release lock on all pages */ 250 + for (i = 0; i < dma->nr_pages; i++) 251 + put_page(dma->pages[i]); 252 + 253 + /* Free allocated dma pages */ 254 + kfree(dma->pages); 255 + dma->sglist = NULL; 256 + 257 + return 0; 258 + } 259 + 260 + int bcm_vk_sg_free(struct device *dev, struct bcm_vk_dma *dma, int num, 261 + int *proc_cnt) 262 + { 263 + int i; 264 + 265 + *proc_cnt = 0; 266 + /* Unmap and free all pages and sglists */ 267 + for (i = 0; i < num; i++) { 268 + if (dma[i].sglist) { 269 + bcm_vk_dma_free(dev, &dma[i]); 270 + *proc_cnt += 1; 271 + } 272 + } 273 + 274 + return 0; 275 + }
+61
drivers/misc/bcm-vk/bcm_vk_sg.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright 2018-2020 Broadcom. 4 + */ 5 + 6 + #ifndef BCM_VK_SG_H 7 + #define BCM_VK_SG_H 8 + 9 + #include <linux/dma-mapping.h> 10 + 11 + struct bcm_vk_dma { 12 + /* for userland buffer */ 13 + struct page **pages; 14 + int nr_pages; 15 + 16 + /* common */ 17 + dma_addr_t handle; 18 + /* 19 + * sglist is of the following LE format 20 + * [U32] num_sg = number of sg addresses (N) 21 + * [U32] totalsize = totalsize of data being transferred in sglist 22 + * [U32] size[0] = size of data in address0 23 + * [U32] addr_l[0] = lower 32-bits of address0 24 + * [U32] addr_h[0] = higher 32-bits of address0 25 + * .. 26 + * [U32] size[N-1] = size of data in addressN-1 27 + * [U32] addr_l[N-1] = lower 32-bits of addressN-1 28 + * [U32] addr_h[N-1] = higher 32-bits of addressN-1 29 + */ 30 + u32 *sglist; 31 + #define SGLIST_NUM_SG 0 32 + #define SGLIST_TOTALSIZE 1 33 + #define SGLIST_VKDATA_START 2 34 + 35 + int sglen; /* Length (bytes) of sglist */ 36 + int direction; 37 + }; 38 + 39 + struct _vk_data { 40 + u32 size; /* data size in bytes */ 41 + u64 address; /* Pointer to data */ 42 + } __packed; 43 + 44 + /* 45 + * Scatter-gather DMA buffer API. 46 + * 47 + * These functions provide a simple way to create a page list and a 48 + * scatter-gather list from userspace address and map the memory 49 + * for DMA operation. 50 + */ 51 + int bcm_vk_sg_alloc(struct device *dev, 52 + struct bcm_vk_dma *dma, 53 + int dir, 54 + struct _vk_data *vkdata, 55 + int num); 56 + 57 + int bcm_vk_sg_free(struct device *dev, struct bcm_vk_dma *dma, int num, 58 + int *proc_cnt); 59 + 60 + #endif 61 +