cregit-Linux how code gets into the kernel

Release 4.11 drivers/misc/mic/host/mic_smpt.c

/*
 * Intel MIC Platform Software Stack (MPSS)
 *
 * Copyright(c) 2013 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * The full GNU General Public License is included in this distribution in
 * the file called "COPYING".
 *
 * Intel MIC Host driver.
 *
 */
#include <linux/pci.h>

#include "../common/mic_dev.h"
#include "mic_device.h"
#include "mic_smpt.h"


static inline u64 mic_system_page_mask(struct mic_device *mdev) { return (1ULL << mdev->smpt->info.page_shift) - 1ULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli27100.00%1100.00%
Total27100.00%1100.00%


static inline u8 mic_sys_addr_to_smpt(struct mic_device *mdev, dma_addr_t pa) { return (pa - mdev->smpt->info.base) >> mdev->smpt->info.page_shift; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli36100.00%1100.00%
Total36100.00%1100.00%


static inline u64 mic_smpt_to_pa(struct mic_device *mdev, u8 index) { return mdev->smpt->info.base + (index * mdev->smpt->info.page_size); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli36100.00%1100.00%
Total36100.00%1100.00%


static inline u64 mic_smpt_offset(struct mic_device *mdev, dma_addr_t pa) { return pa & mic_system_page_mask(mdev); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli23100.00%1100.00%
Total23100.00%1100.00%


static inline u64 mic_smpt_align_low(struct mic_device *mdev, dma_addr_t pa) { return ALIGN(pa - mic_system_page_mask(mdev), mdev->smpt->info.page_size); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli34100.00%1100.00%
Total34100.00%1100.00%


static inline u64 mic_smpt_align_high(struct mic_device *mdev, dma_addr_t pa) { return ALIGN(pa, mdev->smpt->info.page_size); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli29100.00%1100.00%
Total29100.00%1100.00%

/* Total Cumulative system memory accessible by MIC across all SMPT entries */
static inline u64 mic_max_system_memory(struct mic_device *mdev) { return mdev->smpt->info.num_reg * mdev->smpt->info.page_size; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli29100.00%1100.00%
Total29100.00%1100.00%

/* Maximum system memory address accessible by MIC */
static inline u64 mic_max_system_addr(struct mic_device *mdev) { return mdev->smpt->info.base + mic_max_system_memory(mdev) - 1ULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli28100.00%1100.00%
Total28100.00%1100.00%

/* Check if the DMA address is a MIC system memory address */
static inline bool mic_is_system_addr(struct mic_device *mdev, dma_addr_t pa) { return pa >= mdev->smpt->info.base && pa <= mic_max_system_addr(mdev); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli33100.00%1100.00%
Total33100.00%1100.00%

/* Populate an SMPT entry and update the reference counts. */
static void mic_add_smpt_entry(int spt, s64 *ref, u64 addr, int entries, struct mic_device *mdev) { struct mic_smpt_info *smpt_info = mdev->smpt; int i; for (i = spt; i < spt + entries; i++, addr += smpt_info->info.page_size) { if (!smpt_info->entry[i].ref_count && (smpt_info->entry[i].dma_addr != addr)) { mdev->smpt_ops->set(mdev, addr, i); smpt_info->entry[i].dma_addr = addr; } smpt_info->entry[i].ref_count += ref[i - spt]; } }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli128100.00%1100.00%
Total128100.00%1100.00%

/* * Find an available MIC address in MIC SMPT address space * for a given DMA address and size. */
static dma_addr_t mic_smpt_op(struct mic_device *mdev, u64 dma_addr, int entries, s64 *ref, size_t size) { int spt; int ae = 0; int i; unsigned long flags; dma_addr_t mic_addr = 0; dma_addr_t addr = dma_addr; struct mic_smpt_info *smpt_info = mdev->smpt; spin_lock_irqsave(&smpt_info->smpt_lock, flags); /* find existing entries */ for (i = 0; i < smpt_info->info.num_reg; i++) { if (smpt_info->entry[i].dma_addr == addr) { ae++; addr += smpt_info->info.page_size; } else if (ae) /* cannot find contiguous entries */ goto not_found; if (ae == entries) goto found; } /* find free entry */ for (ae = 0, i = 0; i < smpt_info->info.num_reg; i++) { ae = (smpt_info->entry[i].ref_count == 0) ? ae + 1 : 0; if (ae == entries) goto found; } not_found: spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); return mic_addr; found: spt = i - entries + 1; mic_addr = mic_smpt_to_pa(mdev, spt); mic_add_smpt_entry(spt, ref, dma_addr, entries, mdev); smpt_info->map_count++; smpt_info->ref_count += (s64)size; spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); return mic_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli260100.00%1100.00%
Total260100.00%1100.00%

/* * Returns number of smpt entries needed for dma_addr to dma_addr + size * also returns the reference count array for each of those entries * and the starting smpt address */
static int mic_get_smpt_ref_count(struct mic_device *mdev, dma_addr_t dma_addr, size_t size, s64 *ref, u64 *smpt_start) { u64 start = dma_addr; u64 end = dma_addr + size; int i = 0; while (start < end) { ref[i++] = min(mic_smpt_align_high(mdev, start + 1), end) - start; start = mic_smpt_align_high(mdev, start + 1); } if (smpt_start) *smpt_start = mic_smpt_align_low(mdev, dma_addr); return i; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli100100.00%1100.00%
Total100100.00%1100.00%

/* * mic_to_dma_addr - Converts a MIC address to a DMA address. * * @mdev: pointer to mic_device instance. * @mic_addr: MIC address. * * returns a DMA address. */
dma_addr_t mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr) { struct mic_smpt_info *smpt_info = mdev->smpt; int spt; dma_addr_t dma_addr; if (!mic_is_system_addr(mdev, mic_addr)) { dev_err(&mdev->pdev->dev, "mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr); return -EINVAL; } spt = mic_sys_addr_to_smpt(mdev, mic_addr); dma_addr = smpt_info->entry[spt].dma_addr + mic_smpt_offset(mdev, mic_addr); return dma_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli8495.45%133.33%
Ashutosh Dixit33.41%133.33%
Sudeep Dutt11.14%133.33%
Total88100.00%3100.00%

/** * mic_map - Maps a DMA address to a MIC physical address. * * @mdev: pointer to mic_device instance. * @dma_addr: DMA address. * @size: Size of the region to be mapped. * * This API converts the DMA address provided to a DMA address understood * by MIC. Caller should check for errors by calling mic_map_error(..). * * returns DMA address as required by MIC. */
dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size) { dma_addr_t mic_addr = 0; int num_entries; s64 *ref; u64 smpt_start; if (!size || size > mic_max_system_memory(mdev)) return mic_addr; ref = kmalloc_array(mdev->smpt->info.num_reg, sizeof(s64), GFP_ATOMIC); if (!ref) return mic_addr; num_entries = mic_get_smpt_ref_count(mdev, dma_addr, size, ref, &smpt_start); /* Set the smpt table appropriately and get 16G aligned mic address */ mic_addr = mic_smpt_op(mdev, smpt_start, num_entries, ref, size); kfree(ref); /* * If mic_addr is zero then its an error case * since mic_addr can never be zero. * else generate mic_addr by adding the 16G offset in dma_addr */ if (!mic_addr && MIC_FAMILY_X100 == mdev->family) { dev_err(&mdev->pdev->dev, "mic_map failed dma_addr 0x%llx size 0x%lx\n", dma_addr, size); return mic_addr; } else { return mic_addr + mic_smpt_offset(mdev, dma_addr); } }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli15196.18%133.33%
Sudeep Dutt31.91%133.33%
Ashutosh Dixit31.91%133.33%
Total157100.00%3100.00%

/** * mic_unmap - Unmaps a MIC physical address. * * @mdev: pointer to mic_device instance. * @mic_addr: MIC physical address. * @size: Size of the region to be unmapped. * * This API unmaps the mappings created by mic_map(..). * * returns None. */
void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) { struct mic_smpt_info *smpt_info = mdev->smpt; s64 *ref; int num_smpt; int spt; int i; unsigned long flags; if (!size) return; if (!mic_is_system_addr(mdev, mic_addr)) { dev_err(&mdev->pdev->dev, "invalid address: 0x%llx\n", mic_addr); return; } spt = mic_sys_addr_to_smpt(mdev, mic_addr); ref = kmalloc_array(mdev->smpt->info.num_reg, sizeof(s64), GFP_ATOMIC); if (!ref) return; /* Get number of smpt entries to be mapped, ref count array */ num_smpt = mic_get_smpt_ref_count(mdev, mic_addr, size, ref, NULL); spin_lock_irqsave(&smpt_info->smpt_lock, flags); smpt_info->unmap_count++; smpt_info->ref_count -= (s64)size; for (i = spt; i < spt + num_smpt; i++) { smpt_info->entry[i].ref_count -= ref[i - spt]; if (smpt_info->entry[i].ref_count < 0) dev_warn(&mdev->pdev->dev, "ref count for entry %d is negative\n", i); } spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); kfree(ref); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli21696.00%133.33%
Ashutosh Dixit62.67%133.33%
Sudeep Dutt31.33%133.33%
Total225100.00%3100.00%

/** * mic_map_single - Maps a virtual address to a MIC physical address. * * @mdev: pointer to mic_device instance. * @va: Kernel direct mapped virtual address. * @size: Size of the region to be mapped. * * This API calls pci_map_single(..) for the direct mapped virtual address * and then converts the DMA address provided to a DMA address understood * by MIC. Caller should check for errors by calling mic_map_error(..). * * returns DMA address as required by MIC. */
dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size) { dma_addr_t mic_addr = 0; struct pci_dev *pdev = mdev->pdev; dma_addr_t dma_addr = pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL); if (!pci_dma_mapping_error(pdev, dma_addr)) { mic_addr = mic_map(mdev, dma_addr, size); if (!mic_addr) { dev_err(&mdev->pdev->dev, "mic_map failed dma_addr 0x%llx size 0x%lx\n", dma_addr, size); pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); } } return mic_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli10196.19%150.00%
Ashutosh Dixit43.81%150.00%
Total105100.00%2100.00%

/** * mic_unmap_single - Unmaps a MIC physical address. * * @mdev: pointer to mic_device instance. * @mic_addr: MIC physical address. * @size: Size of the region to be unmapped. * * This API unmaps the mappings created by mic_map_single(..). * * returns None. */
void mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size) { struct pci_dev *pdev = mdev->pdev; dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr); mic_unmap(mdev, mic_addr, size); pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli5498.18%150.00%
Ashutosh Dixit11.82%150.00%
Total55100.00%2100.00%

/** * mic_smpt_init - Initialize MIC System Memory Page Tables. * * @mdev: pointer to mic_device instance. * * returns 0 for success and -errno for error. */
int mic_smpt_init(struct mic_device *mdev) { int i, err = 0; dma_addr_t dma_addr; struct mic_smpt_info *smpt_info; mdev->smpt = kmalloc(sizeof(*mdev->smpt), GFP_KERNEL); if (!mdev->smpt) return -ENOMEM; smpt_info = mdev->smpt; mdev->smpt_ops->init(mdev); smpt_info->entry = kmalloc_array(smpt_info->info.num_reg, sizeof(*smpt_info->entry), GFP_KERNEL); if (!smpt_info->entry) { err = -ENOMEM; goto free_smpt; } spin_lock_init(&smpt_info->smpt_lock); for (i = 0; i < smpt_info->info.num_reg; i++) { dma_addr = i * smpt_info->info.page_size; smpt_info->entry[i].dma_addr = dma_addr; smpt_info->entry[i].ref_count = 0; mdev->smpt_ops->set(mdev, dma_addr, i); } smpt_info->ref_count = 0; smpt_info->map_count = 0; smpt_info->unmap_count = 0; return 0; free_smpt: kfree(smpt_info); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli20295.73%150.00%
Ashutosh Dixit94.27%150.00%
Total211100.00%2100.00%

/** * mic_smpt_uninit - UnInitialize MIC System Memory Page Tables. * * @mdev: pointer to mic_device instance. * * returns None. */
void mic_smpt_uninit(struct mic_device *mdev) { struct mic_smpt_info *smpt_info = mdev->smpt; int i; dev_dbg(&mdev->pdev->dev, "nodeid %d SMPT ref count %lld map %lld unmap %lld\n", mdev->id, smpt_info->ref_count, smpt_info->map_count, smpt_info->unmap_count); for (i = 0; i < smpt_info->info.num_reg; i++) { dev_dbg(&mdev->pdev->dev, "SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n", i, smpt_info->entry[i].dma_addr, smpt_info->entry[i].ref_count); if (smpt_info->entry[i].ref_count) dev_warn(&mdev->pdev->dev, "ref count for entry %d is not zero\n", i); } kfree(smpt_info->entry); kfree(smpt_info); }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli12993.48%150.00%
Ashutosh Dixit96.52%150.00%
Total138100.00%2100.00%

/** * mic_smpt_restore - Restore MIC System Memory Page Tables. * * @mdev: pointer to mic_device instance. * * Restore the SMPT registers to values previously stored in the * SW data structures. Some MIC steppings lose register state * across resets and this API should be called for performing * a restore operation if required. * * returns None. */
void mic_smpt_restore(struct mic_device *mdev) { int i; dma_addr_t dma_addr; for (i = 0; i < mdev->smpt->info.num_reg; i++) { dma_addr = mdev->smpt->entry[i].dma_addr; mdev->smpt_ops->set(mdev, dma_addr, i); } }

Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli63100.00%1100.00%
Total63100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Dasaratharaman Chandramouli178997.65%120.00%
Ashutosh Dixit351.91%240.00%
Sudeep Dutt80.44%240.00%
Total1832100.00%5100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.