cregit-Linux how code gets into the kernel

Release 4.7 drivers/infiniband/hw/usnic/usnic_vnic.c

/*
 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>

#include "usnic_ib.h"
#include "vnic_resource.h"
#include "usnic_log.h"
#include "usnic_vnic.h"


struct usnic_vnic {
	
struct vnic_dev			*vdev;
	
struct vnic_dev_bar		bar[PCI_NUM_RESOURCES];
	
struct usnic_vnic_res_chunk	chunks[USNIC_VNIC_RES_TYPE_MAX];
	
spinlock_t			res_lock;
};


static enum vnic_res_type _to_vnic_res_type(enum usnic_vnic_res_type res_type) { #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \ vnic_res_type, #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \ vnic_res_type, static enum vnic_res_type usnic_vnic_type_2_vnic_type[] = { USNIC_VNIC_RES_TYPES}; #undef DEFINE_USNIC_VNIC_RES #undef DEFINE_USNIC_VNIC_RES_AT if (res_type >= USNIC_VNIC_RES_TYPE_MAX) return RES_TYPE_MAX; return usnic_vnic_type_2_vnic_type[res_type]; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi68100.00%1100.00%
Total68100.00%1100.00%


const char *usnic_vnic_res_type_to_str(enum usnic_vnic_res_type res_type) { #define DEFINE_USNIC_VNIC_RES_AT(usnic_vnic_res_t, vnic_res_type, desc, val) \ desc, #define DEFINE_USNIC_VNIC_RES(usnic_vnic_res_t, vnic_res_type, desc) \ desc, static const char * const usnic_vnic_res_type_desc[] = { USNIC_VNIC_RES_TYPES}; #undef DEFINE_USNIC_VNIC_RES #undef DEFINE_USNIC_VNIC_RES_AT if (res_type >= USNIC_VNIC_RES_TYPE_MAX) return "unknown"; return usnic_vnic_res_type_desc[res_type]; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi70100.00%1100.00%
Total70100.00%1100.00%


const char *usnic_vnic_pci_name(struct usnic_vnic *vnic) { return pci_name(usnic_vnic_get_pdev(vnic)); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi21100.00%1100.00%
Total21100.00%1100.00%


int usnic_vnic_dump(struct usnic_vnic *vnic, char *buf, int buf_sz, void *hdr_obj, int (*printtitle)(void *, char*, int), int (*printcols)(char *, int), int (*printrow)(void *, char *, int)) { struct usnic_vnic_res_chunk *chunk; struct usnic_vnic_res *res; struct vnic_dev_bar *bar0; int i, j, offset; offset = 0; bar0 = usnic_vnic_get_bar(vnic, 0); offset += scnprintf(buf + offset, buf_sz - offset, "VF:%hu BAR0 bus_addr=%pa vaddr=0x%p size=%ld ", usnic_vnic_get_index(vnic), &bar0->bus_addr, bar0->vaddr, bar0->len); if (printtitle) offset += printtitle(hdr_obj, buf + offset, buf_sz - offset); offset += scnprintf(buf + offset, buf_sz - offset, "\n"); offset += scnprintf(buf + offset, buf_sz - offset, "|RES\t|CTRL_PIN\t\t|IN_USE\t"); if (printcols) offset += printcols(buf + offset, buf_sz - offset); offset += scnprintf(buf + offset, buf_sz - offset, "\n"); spin_lock(&vnic->res_lock); for (i = 0; i < ARRAY_SIZE(vnic->chunks); i++) { chunk = &vnic->chunks[i]; for (j = 0; j < chunk->cnt; j++) { res = chunk->res[j]; offset += scnprintf(buf + offset, buf_sz - offset, "|%s[%u]\t|0x%p\t|%u\t", usnic_vnic_res_type_to_str(res->type), res->vnic_idx, res->ctrl, !!res->owner); if (printrow) { offset += printrow(res->owner, buf + offset, buf_sz - offset); } offset += scnprintf(buf + offset, buf_sz - offset, "\n"); } } spin_unlock(&vnic->res_lock); return offset; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi361100.00%1100.00%
Total361100.00%1100.00%


void usnic_vnic_res_spec_update(struct usnic_vnic_res_spec *spec, enum usnic_vnic_res_type trgt_type, u16 cnt) { int i; for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) { if (spec->resources[i].type == trgt_type) { spec->resources[i].cnt = cnt; return; } } WARN_ON(1); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi67100.00%1100.00%
Total67100.00%1100.00%


int usnic_vnic_res_spec_satisfied(const struct usnic_vnic_res_spec *min_spec, struct usnic_vnic_res_spec *res_spec) { int found, i, j; for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) { found = 0; for (j = 0; j < USNIC_VNIC_RES_TYPE_MAX; j++) { if (res_spec->resources[i].type != min_spec->resources[i].type) continue; found = 1; if (min_spec->resources[i].cnt > res_spec->resources[i].cnt) return -EINVAL; break; } if (!found) return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi119100.00%1100.00%
Total119100.00%1100.00%


int usnic_vnic_spec_dump(char *buf, int buf_sz, struct usnic_vnic_res_spec *res_spec) { enum usnic_vnic_res_type res_type; int res_cnt; int i; int offset = 0; for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) { res_type = res_spec->resources[i].type; res_cnt = res_spec->resources[i].cnt; offset += scnprintf(buf + offset, buf_sz - offset, "Res: %s Cnt: %d ", usnic_vnic_res_type_to_str(res_type), res_cnt); } return offset; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi94100.00%1100.00%
Total94100.00%1100.00%


int usnic_vnic_check_room(struct usnic_vnic *vnic, struct usnic_vnic_res_spec *res_spec) { int i; enum usnic_vnic_res_type res_type; int res_cnt; for (i = 0; i < USNIC_VNIC_RES_TYPE_MAX; i++) { res_type = res_spec->resources[i].type; res_cnt = res_spec->resources[i].cnt; if (res_type == USNIC_VNIC_RES_TYPE_EOL) break; if (res_cnt > usnic_vnic_res_free_cnt(vnic, res_type)) return -EBUSY; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi87100.00%1100.00%
Total87100.00%1100.00%


int usnic_vnic_res_cnt(struct usnic_vnic *vnic, enum usnic_vnic_res_type type) { return vnic->chunks[type].cnt; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi24100.00%1100.00%
Total24100.00%1100.00%


int usnic_vnic_res_free_cnt(struct usnic_vnic *vnic, enum usnic_vnic_res_type type) { return vnic->chunks[type].free_cnt; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi24100.00%1100.00%
Total24100.00%1100.00%


struct usnic_vnic_res_chunk * usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type, int cnt, void *owner) { struct usnic_vnic_res_chunk *src, *ret; struct usnic_vnic_res *res; int i; if (usnic_vnic_res_free_cnt(vnic, type) < cnt || cnt < 0 || !owner) return ERR_PTR(-EINVAL); ret = kzalloc(sizeof(*ret), GFP_ATOMIC); if (!ret) { usnic_err("Failed to allocate chunk for %s - Out of memory\n", usnic_vnic_pci_name(vnic)); return ERR_PTR(-ENOMEM); } if (cnt > 0) { ret->res = kcalloc(cnt, sizeof(*(ret->res)), GFP_ATOMIC); if (!ret->res) { usnic_err("Failed to allocate resources for %s. Out of memory\n", usnic_vnic_pci_name(vnic)); kfree(ret); return ERR_PTR(-ENOMEM); } spin_lock(&vnic->res_lock); src = &vnic->chunks[type]; for (i = 0; i < src->cnt && ret->cnt < cnt; i++) { res = src->res[i]; if (!res->owner) { src->free_cnt--; res->owner = owner; ret->res[ret->cnt++] = res; } } spin_unlock(&vnic->res_lock); } ret->type = type; ret->vnic = vnic; WARN_ON(ret->cnt != cnt); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi26395.64%150.00%
nelson escobarnelson escobar124.36%150.00%
Total275100.00%2100.00%


void usnic_vnic_put_resources(struct usnic_vnic_res_chunk *chunk) { struct usnic_vnic_res *res; int i; struct usnic_vnic *vnic = chunk->vnic; if (chunk->cnt > 0) { spin_lock(&vnic->res_lock); while ((i = --chunk->cnt) >= 0) { res = chunk->res[i]; chunk->res[i] = NULL; res->owner = NULL; vnic->chunks[res->type].free_cnt++; } spin_unlock(&vnic->res_lock); } kfree(chunk->res); kfree(chunk); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi10691.38%150.00%
nelson escobarnelson escobar108.62%150.00%
Total116100.00%2100.00%


u16 usnic_vnic_get_index(struct usnic_vnic *vnic) { return usnic_vnic_get_pdev(vnic)->devfn - 1; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi20100.00%1100.00%
Total20100.00%1100.00%


static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic, enum usnic_vnic_res_type type, struct usnic_vnic_res_chunk *chunk) { int cnt, err, i; struct usnic_vnic_res *res; cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type)); if (cnt < 1) return -EINVAL; chunk->cnt = chunk->free_cnt = cnt; chunk->res = kzalloc(sizeof(*(chunk->res))*cnt, GFP_KERNEL); if (!chunk->res) return -ENOMEM; for (i = 0; i < cnt; i++) { res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) { err = -ENOMEM; goto fail; } res->type = type; res->vnic_idx = i; res->vnic = vnic; res->ctrl = vnic_dev_get_res(vnic->vdev, _to_vnic_res_type(type), i); chunk->res[i] = res; } chunk->vnic = vnic; return 0; fail: for (i--; i >= 0; i--) kfree(chunk->res[i]); kfree(chunk->res); return err; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi229100.00%1100.00%
Total229100.00%1100.00%


static void usnic_vnic_free_res_chunk(struct usnic_vnic_res_chunk *chunk) { int i; for (i = 0; i < chunk->cnt; i++) kfree(chunk->res[i]); kfree(chunk->res); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi46100.00%1100.00%
Total46100.00%1100.00%


static int usnic_vnic_discover_resources(struct pci_dev *pdev, struct usnic_vnic *vnic) { enum usnic_vnic_res_type res_type; int i; int err = 0; for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) { if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) continue; vnic->bar[i].len = pci_resource_len(pdev, i); vnic->bar[i].vaddr = pci_iomap(pdev, i, vnic->bar[i].len); if (!vnic->bar[i].vaddr) { usnic_err("Cannot memory-map BAR %d, aborting\n", i); err = -ENODEV; goto out_clean_bar; } vnic->bar[i].bus_addr = pci_resource_start(pdev, i); } vnic->vdev = vnic_dev_register(NULL, pdev, pdev, vnic->bar, ARRAY_SIZE(vnic->bar)); if (!vnic->vdev) { usnic_err("Failed to register device %s\n", pci_name(pdev)); err = -EINVAL; goto out_clean_bar; } for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1; res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) { err = usnic_vnic_alloc_res_chunk(vnic, res_type, &vnic->chunks[res_type]); if (err) { usnic_err("Failed to alloc res %s with err %d\n", usnic_vnic_res_type_to_str(res_type), err); goto out_clean_chunks; } } return 0; out_clean_chunks: for (res_type--; res_type > USNIC_VNIC_RES_TYPE_EOL; res_type--) usnic_vnic_free_res_chunk(&vnic->chunks[res_type]); vnic_dev_unregister(vnic->vdev); out_clean_bar: for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) { if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) continue; if (!vnic->bar[i].vaddr) break; iounmap(vnic->bar[i].vaddr); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi355100.00%1100.00%
Total355100.00%1100.00%


struct pci_dev *usnic_vnic_get_pdev(struct usnic_vnic *vnic) { return vnic_dev_get_pdev(vnic->vdev); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi20100.00%1100.00%
Total20100.00%1100.00%


struct vnic_dev_bar *usnic_vnic_get_bar(struct usnic_vnic *vnic, int bar_num) { return (bar_num < ARRAY_SIZE(vnic->bar)) ? &vnic->bar[bar_num] : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi37100.00%1100.00%
Total37100.00%1100.00%


static void usnic_vnic_release_resources(struct usnic_vnic *vnic) { int i; struct pci_dev *pdev; enum usnic_vnic_res_type res_type; pdev = usnic_vnic_get_pdev(vnic); for (res_type = USNIC_VNIC_RES_TYPE_EOL + 1; res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) usnic_vnic_free_res_chunk(&vnic->chunks[res_type]); vnic_dev_unregister(vnic->vdev); for (i = 0; i < ARRAY_SIZE(vnic->bar); i++) { if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) continue; iounmap(vnic->bar[i].vaddr); } }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi110100.00%1100.00%
Total110100.00%1100.00%


struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev) { struct usnic_vnic *vnic; int err = 0; if (!pci_is_enabled(pdev)) { usnic_err("PCI dev %s is disabled\n", pci_name(pdev)); return ERR_PTR(-EINVAL); } vnic = kzalloc(sizeof(*vnic), GFP_KERNEL); if (!vnic) { usnic_err("Failed to alloc vnic for %s - out of memory\n", pci_name(pdev)); return ERR_PTR(-ENOMEM); } spin_lock_init(&vnic->res_lock); err = usnic_vnic_discover_resources(pdev, vnic); if (err) { usnic_err("Failed to discover %s resources with err %d\n", pci_name(pdev), err); goto out_free_vnic; } usnic_dbg("Allocated vnic for %s\n", usnic_vnic_pci_name(vnic)); return vnic; out_free_vnic: kfree(vnic); return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi150100.00%1100.00%
Total150100.00%1100.00%


void usnic_vnic_free(struct usnic_vnic *vnic) { usnic_vnic_release_resources(vnic); kfree(vnic); }

Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi20100.00%1100.00%
Total20100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
upinder malhiupinder malhi233999.03%133.33%
nelson escobarnelson escobar220.93%133.33%
jeff squyresjeff squyres10.04%133.33%
Total2362100.00%3100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}