Skip to content

Commit

Permalink
s390/ap: introduce new ap function ap_get_qdev()
Browse files Browse the repository at this point in the history
Provide a new interface function to be used by the ap drivers:
  struct ap_queue *ap_get_qdev(ap_qid_t qid);
Returns ptr to the struct ap_queue device or NULL if there
was no ap_queue device with this qid found. When something is
found, the reference count of the embedded device is increased.
So the caller has to decrease the reference count after use
with a call to put_device(&aq->ap_dev.device).

With this patch also the ap_card_list is removed from the
ap core code and a new hashtable is introduced which stores
hnodes of all the ap queues known to the ap bus.

The hashtable approach and a first implementation of this
interface comes from a previous patch from
Anthony Krowiak and an idea from Halil Pasic.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Suggested-by: Tony Krowiak <akrowiak@linux.ibm.com>
Suggested-by: Halil Pasic <pasic@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
  • Loading branch information
Harald Freudenberger authored and Vasily Gorbik committed May 20, 2020
1 parent d03756a commit bc4b295
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 81 deletions.
94 changes: 54 additions & 40 deletions drivers/s390/crypto/ap_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ MODULE_PARM_DESC(aqmask, "AP bus domain mask.");

static struct device *ap_root_device;

DEFINE_SPINLOCK(ap_list_lock);
LIST_HEAD(ap_card_list);
/* Hashtable of all queue devices on the AP bus */
DEFINE_HASHTABLE(ap_queues, 8);
/* lock used for the ap_queues hashtable */
DEFINE_SPINLOCK(ap_queues_lock);

/* Default permissions (ioctl, card and domain masking) */
struct ap_perms ap_perms;
Expand Down Expand Up @@ -414,7 +416,7 @@ static void ap_interrupt_handler(struct airq_struct *airq, bool floating)
*/
static void ap_tasklet_fn(unsigned long dummy)
{
struct ap_card *ac;
int bkt;
struct ap_queue *aq;
enum ap_wait wait = AP_WAIT_NONE;

Expand All @@ -425,34 +427,30 @@ static void ap_tasklet_fn(unsigned long dummy)
if (ap_using_interrupts())
xchg(ap_airq.lsi_ptr, 0);

spin_lock_bh(&ap_list_lock);
for_each_ap_card(ac) {
for_each_ap_queue(aq, ac) {
spin_lock_bh(&aq->lock);
wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode) {
spin_lock_bh(&aq->lock);
wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL));
spin_unlock_bh(&aq->lock);
}
spin_unlock_bh(&ap_list_lock);
spin_unlock_bh(&ap_queues_lock);

ap_wait(wait);
}

static int ap_pending_requests(void)
{
struct ap_card *ac;
int bkt;
struct ap_queue *aq;

spin_lock_bh(&ap_list_lock);
for_each_ap_card(ac) {
for_each_ap_queue(aq, ac) {
if (aq->queue_count == 0)
continue;
spin_unlock_bh(&ap_list_lock);
return 1;
}
spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode) {
if (aq->queue_count == 0)
continue;
spin_unlock_bh(&ap_queues_lock);
return 1;
}
spin_unlock_bh(&ap_list_lock);
spin_unlock_bh(&ap_queues_lock);
return 0;
}

Expand Down Expand Up @@ -683,24 +681,20 @@ static int ap_device_probe(struct device *dev)
}

/* Add queue/card to list of active queues/cards */
spin_lock_bh(&ap_list_lock);
if (is_card_dev(dev))
list_add(&to_ap_card(dev)->list, &ap_card_list);
else
list_add(&to_ap_queue(dev)->list,
&to_ap_queue(dev)->card->queues);
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
if (is_queue_dev(dev))
hash_add(ap_queues, &to_ap_queue(dev)->hnode,
to_ap_queue(dev)->qid);
spin_unlock_bh(&ap_queues_lock);

ap_dev->drv = ap_drv;
rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;

if (rc) {
spin_lock_bh(&ap_list_lock);
if (is_card_dev(dev))
list_del_init(&to_ap_card(dev)->list);
else
list_del_init(&to_ap_queue(dev)->list);
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
if (is_queue_dev(dev))
hash_del(&to_ap_queue(dev)->hnode);
spin_unlock_bh(&ap_queues_lock);
ap_dev->drv = NULL;
}

Expand All @@ -725,16 +719,33 @@ static int ap_device_remove(struct device *dev)
ap_queue_remove(to_ap_queue(dev));

/* Remove queue/card from list of active queues/cards */
spin_lock_bh(&ap_list_lock);
if (is_card_dev(dev))
list_del_init(&to_ap_card(dev)->list);
else
list_del_init(&to_ap_queue(dev)->list);
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
if (is_queue_dev(dev))
hash_del(&to_ap_queue(dev)->hnode);
spin_unlock_bh(&ap_queues_lock);

return 0;
}

struct ap_queue *ap_get_qdev(ap_qid_t qid)
{
int bkt;
struct ap_queue *aq;

spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode) {
if (aq->qid == qid) {
get_device(&aq->ap_dev.device);
spin_unlock_bh(&ap_queues_lock);
return aq;
}
}
spin_unlock_bh(&ap_queues_lock);

return NULL;
}
EXPORT_SYMBOL(ap_get_qdev);

int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
char *name)
{
Expand Down Expand Up @@ -1506,6 +1517,9 @@ static int __init ap_module_init(void)
return -ENODEV;
}

/* init ap_queue hashtable */
hash_init(ap_queues);

/* set up the AP permissions (ioctls, ap and aq masks) */
ap_perms_init();

Expand Down
25 changes: 14 additions & 11 deletions drivers/s390/crypto/ap_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <linux/device.h>
#include <linux/types.h>
#include <linux/hashtable.h>
#include <asm/isc.h>
#include <asm/ap.h>

Expand All @@ -27,8 +28,8 @@

extern int ap_domain_index;

extern spinlock_t ap_list_lock;
extern struct list_head ap_card_list;
extern DECLARE_HASHTABLE(ap_queues, 8);
extern spinlock_t ap_queues_lock;

static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
{
Expand Down Expand Up @@ -152,8 +153,6 @@ struct ap_device {

struct ap_card {
struct ap_device ap_dev;
struct list_head list; /* Private list of AP cards. */
struct list_head queues; /* List of assoc. AP queues */
void *private; /* ap driver private pointer. */
int raw_hwtype; /* AP raw hardware type. */
unsigned int functions; /* AP device function bitfield. */
Expand All @@ -166,7 +165,7 @@ struct ap_card {

struct ap_queue {
struct ap_device ap_dev;
struct list_head list; /* Private list of AP queues. */
struct hlist_node hnode; /* Node for the ap_queues hashtable */
struct ap_card *card; /* Ptr to assoc. AP card. */
spinlock_t lock; /* Per device lock. */
void *private; /* ap driver private pointer. */
Expand Down Expand Up @@ -223,12 +222,6 @@ static inline void ap_release_message(struct ap_message *ap_msg)
kzfree(ap_msg->private);
}

#define for_each_ap_card(_ac) \
list_for_each_entry(_ac, &ap_card_list, list)

#define for_each_ap_queue(_aq, _ac) \
list_for_each_entry(_aq, &(_ac)->queues, list)

/*
* Note: don't use ap_send/ap_recv after using ap_queue_message
* for the first time. Otherwise the ap message queue will get
Expand Down Expand Up @@ -269,6 +262,16 @@ struct ap_perms {
extern struct ap_perms ap_perms;
extern struct mutex ap_perms_mutex;

/*
* Get ap_queue device for this qid.
* Returns ptr to the struct ap_queue device or NULL if there
* was no ap_queue device with this qid found. When something is
* found, the reference count of the embedded device is increased.
* So the caller has to decrease the reference count after use
* with a call to put_device(&aq->ap_dev.device).
*/
struct ap_queue *ap_get_qdev(ap_qid_t qid);

/*
* check APQN for owned/reserved by ap bus and default driver(s).
* Checks if this APQN is or will be in use by the ap bus
Expand Down
47 changes: 23 additions & 24 deletions drivers/s390/crypto/ap_card.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,25 @@ static ssize_t request_count_show(struct device *dev,
u64 req_cnt;

req_cnt = 0;
spin_lock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
req_cnt = atomic64_read(&ac->total_request_count);
spin_unlock_bh(&ap_list_lock);
spin_unlock_bh(&ap_queues_lock);
return scnprintf(buf, PAGE_SIZE, "%llu\n", req_cnt);
}

static ssize_t request_count_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ap_card *ac = to_ap_card(dev);
int bkt;
struct ap_queue *aq;
struct ap_card *ac = to_ap_card(dev);

spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
aq->total_request_count = 0;
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode)
if (ac == aq->card)
aq->total_request_count = 0;
spin_unlock_bh(&ap_queues_lock);
atomic64_set(&ac->total_request_count, 0);

return count;
Expand All @@ -93,15 +95,17 @@ static DEVICE_ATTR_RW(request_count);
static ssize_t requestq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
int bkt;
struct ap_queue *aq;
unsigned int reqq_cnt;
struct ap_card *ac = to_ap_card(dev);

reqq_cnt = 0;
spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
reqq_cnt += aq->requestq_count;
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode)
if (ac == aq->card)
reqq_cnt += aq->requestq_count;
spin_unlock_bh(&ap_queues_lock);
return scnprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt);
}

Expand All @@ -110,15 +114,17 @@ static DEVICE_ATTR_RO(requestq_count);
static ssize_t pendingq_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ap_card *ac = to_ap_card(dev);
int bkt;
struct ap_queue *aq;
unsigned int penq_cnt;
struct ap_card *ac = to_ap_card(dev);

penq_cnt = 0;
spin_lock_bh(&ap_list_lock);
for_each_ap_queue(aq, ac)
penq_cnt += aq->pendingq_count;
spin_unlock_bh(&ap_list_lock);
spin_lock_bh(&ap_queues_lock);
hash_for_each(ap_queues, bkt, aq, hnode)
if (ac == aq->card)
penq_cnt += aq->pendingq_count;
spin_unlock_bh(&ap_queues_lock);
return scnprintf(buf, PAGE_SIZE, "%d\n", penq_cnt);
}

Expand Down Expand Up @@ -163,11 +169,6 @@ static void ap_card_device_release(struct device *dev)
{
struct ap_card *ac = to_ap_card(dev);

if (!list_empty(&ac->list)) {
spin_lock_bh(&ap_list_lock);
list_del_init(&ac->list);
spin_unlock_bh(&ap_list_lock);
}
kfree(ac);
}

Expand All @@ -179,8 +180,6 @@ struct ap_card *ap_card_create(int id, int queue_depth, int raw_type,
ac = kzalloc(sizeof(*ac), GFP_KERNEL);
if (!ac)
return NULL;
INIT_LIST_HEAD(&ac->list);
INIT_LIST_HEAD(&ac->queues);
ac->ap_dev.device.release = ap_card_device_release;
ac->ap_dev.device.type = &ap_card_type;
ac->ap_dev.device_type = comp_type;
Expand Down
10 changes: 4 additions & 6 deletions drivers/s390/crypto/ap_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,10 @@ static void ap_queue_device_release(struct device *dev)
{
struct ap_queue *aq = to_ap_queue(dev);

if (!list_empty(&aq->list)) {
spin_lock_bh(&ap_list_lock);
list_del_init(&aq->list);
spin_unlock_bh(&ap_list_lock);
}
spin_lock_bh(&ap_queues_lock);
hash_del(&aq->hnode);
spin_unlock_bh(&ap_queues_lock);

kfree(aq);
}

Expand All @@ -590,7 +589,6 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
aq->state = AP_STATE_UNBOUND;
aq->interrupt = AP_INTR_DISABLED;
spin_lock_init(&aq->lock);
INIT_LIST_HEAD(&aq->list);
INIT_LIST_HEAD(&aq->pendingq);
INIT_LIST_HEAD(&aq->requestq);
timer_setup(&aq->timeout, ap_request_timeout, 0);
Expand Down

0 comments on commit bc4b295

Please sign in to comment.